【问题标题】:How to group a list of points?如何对点列表进行分组?
【发布时间】:2019-10-11 17:25:13
【问题描述】:

假设我有一个点列表,如果它们在平面上,它看起来像这样:

如何将它们分成四 (4) 组点?

【问题讨论】:

  • 取第一点。测量到所有其他点的所有距离。对它们进行排序。距离之间会有差距。所有低于这个差距的人都将进入第一组。继续第一个未分组的点。重复直到没有剩余的未分组点。
  • Relatedthe Wikipedia article,可能有一些指针。
  • 不幸的是,这是一个非常广泛的问题。您可能认为对于您所展示的确切问题,该算法相当简单,并且您可能是对的,但只需将两个组靠得更近一点,问题就会变得非常混乱。例如,这里有一篇关于这个问题的codeproject 文章,正如你所见,它毕竟看起来并不那么简单。
  • 举个例子,如果你看左下组,如果在那个组中,你考虑右上角点到左下点的距离,看起来这个距离和距离很相似直到点的中心组。换句话说,这两点之间的距离是不够的,必须是你可以用额外的点来弥补这两点之间的差距,使距离标准变得更低。
  • 一个简单的实现是将组编号分配给点,当两个点足够接近时,您可以用另一组的编号覆盖其中一个组的组编号。例如,如果 A 点在第 1 组中,B 点在第 2 组中,并且 A 和 B 足够接近以被认为是同一组,则将第 2 组中的所有点重新编号为第 1 组(或相反),这样您就可以轻松地将其与当前图片分组。但是,如果组更接近,则使用它并不安全,您可能需要高级边缘拓扑检测来将它们分开。

标签: c#


【解决方案1】:

我们可以重写 equals 方法来检查 Points 是否相等。在 equals 方法中添加适当的容差

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;
        }
    }
}

我们可以在下面使用点添加组

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;
    }
}

【讨论】:

  • 我不会重写 equals 来处理这个问题,因为这也应该重写 GetHashCode,在这种情况下没有办法这样做。相反,创建一个单独的分组实现。 Equals 应该是可传递的,换句话说,如果 a==b 和 b==c,则 a==c,并且无法通过距离获得该属性,因为 a 可能在与 b 的距离内,并且b 到 c,但 a 和 c 之间的距离可能太大。但是,如果您只是将 Equals 重命名为“IsCloseEnoughTo”,并将一个点作为参数,那就没问题了。只是不要(ab)为此使用 Equals。
  • @LasseVågsætherKarlsen 。编写 equals 方法时没有考虑传递性。需要改方法名。
猜你喜欢
  • 2015-04-07
  • 1970-01-01
  • 2021-07-11
  • 2021-02-11
  • 1970-01-01
  • 1970-01-01
  • 2023-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多