0

Suppose I have a list of points and if they are in a plane, it would look like this:

enter image description here

How do I group them into Four(4) groups of points?

ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
TerribleDog
  • 1,237
  • 1
  • 8
  • 31
  • What is the grouping criteria? – Chetan Oct 11 '19 at 04:01
  • @ChetanRanpariya the distances. If the points seem to be near each other like in the image, they should be in one group. – TerribleDog Oct 11 '19 at 04:09
  • https://stackoverflow.com/questions/11555355/calculating-the-distance-between-2-points – Chetan Oct 11 '19 at 04:11
  • If you're looking for a "PointList.GroupPoints()", I'm afraid that there's nothing built-in. – ProgrammingLlama Oct 11 '19 at 04:59
  • @John I don't. I'm actually looking for the algorithm on how to cluster the list of points based on their distance. – TerribleDog Oct 11 '19 at 05:00
  • Is the entire area and group numbers are certain? if not it will be complicate I'm afraid. – Jarvan Oct 11 '19 at 05:03
  • @Jarvan It will vary depending on the data to be used. – TerribleDog Oct 11 '19 at 05:05
  • 1
    Take the first point. Measure all the distance to all other points. Sort them. There will be a gap between the distances. All below this gap will go to the first group. Go on with the first ungrouped point. Repeat until there is no ungrouped point left. – SomeBody Oct 11 '19 at 05:06
  • 1
    [Related](https://stackoverflow.com/questions/356035/algorithm-for-detecting-clusters-of-dots) and [the Wikipedia article](https://en.wikipedia.org/wiki/Cluster_analysis), which might have some pointers. – ProgrammingLlama Oct 11 '19 at 05:08
  • @SomeBody Thanks. That's exactly what I'm working on right now. I already have the sorted list. – TerribleDog Oct 11 '19 at 05:08
  • @TerribleDog: So where are you stuck? Post your code what you achieved so far. – SomeBody Oct 11 '19 at 05:15
  • @SomeBody I'll be posting it later after I tried your suggestion and something doesn't work. I'll also post it if it works just like you said :) – TerribleDog Oct 11 '19 at 05:22
  • 2
    This is unfortunately a very broad question. You may think that the algorithm would be fairly simple for the exact problem you've shown, and you'd probably be right, but all it takes is to move two of the groups a bit closer together and the problem becomes very muddy. As an example, here's a [codeproject](https://www.codeproject.com/Articles/1120804/Finding-groups-in-data-with-Csharp-Agglomerative-C) article about this problem, as you can see it doesn't seem so simple after all. – Lasse V. Karlsen Oct 11 '19 at 08:59
  • 2
    As an example, if you look at the bottom left group, if, in that group, you consider the top right point distance to the bottom left point, it seems this distance is quite similar to the distance up to the center group of points. In other words, the distance between these two points can't be enough, it has to be that you can bridge the gap between those two points with additional points so that the distance criteria becomes lower. – Lasse V. Karlsen Oct 11 '19 at 09:01
  • 2
    A simple implementation would be to assign group numbers to points, and when two points are close enough, you override the group numbers of one of the groups with the number of the other group. For instance, if point A is in group 1, and point B is in group 2, and A and B are close enough to be considered the same group, renumber all points in group 2 to be in group 1 (or the opposite), this would then easily allow you to group it with your current picture. It would not, however, be safe to use if groups are closer, you might then need advanced edge topology detection to separate them. – Lasse V. Karlsen Oct 11 '19 at 09:04

1 Answers1

1

We can override the equals method to check the Points are equal or not . Add appropriate tolerance in the equals method

public class Point
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }


    public bool AreEquals(object obj,double tolerance)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }

        Point obj1 = (Point)obj;
        var absX = Math.Pow(X - obj1.X, 2);
        var absY = Math.Pow(Y - obj1.Y, 2);
        var absZ = Math.Pow(Z - obj1.Z, 2);

        if (Math.Abs(absX + absY + absZ) >= tolerance)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}

We can add the group the Points using below

public class PointGroup
{
    public int GroupID { get; set; }
    public Point Point1 { get; set; }
    public bool IsGrouped { get; set; }
}
for (int i = 0; i < coll.Count(); i++)
{
    PointGroup pg1 = coll[i];
    if (!pg1.IsGrouped)
    {
        for (int j = 0; j < coll.Count(); j++)
        {
            PointGroup pg2 = coll[j];
            if (pg1.Point1.AreEquals(pg2.Point1,0.1) && pg2.IsGrouped == false)
            {
                if (pg2.GroupID == j)
                {
                    pg2.GroupID = pg1.GroupID;
                    pg2.IsGrouped = true;
                }
            }
        }

        pg1.IsGrouped = true;
    }
}
Test12345
  • 1,625
  • 1
  • 12
  • 21
  • 3
    I would not override equals to handle this, as this should also override GetHashCode, and there's no way to do that in this case. Instead, create a separate grouping implementation. Equals is supposed to be transitive, in other words if a==b and b==c, then a==c, and there is no way to get that property with distance, as a might be within the distance to b, and b to c, but the distance between a and c might be too large. However, if you simply renamed Equals to "IsCloseEnoughTo", and take a point as a parameter, it would be fine. Just don't (ab)use Equals for this. – Lasse V. Karlsen Oct 11 '19 at 09:01
  • @LasseVågsætherKarlsen . Didnt consider the transitive property while writing the equals method . Need to change the method name . – Test12345 Oct 11 '19 at 09:21