【问题标题】:Efficiently find point of insertion for new point in list of clockwise sorted points (around a central point)在顺时针排序的点列表中有效地找到新点的插入点(围绕中心点)
【发布时间】:2018-03-22 17:02:10
【问题描述】:

假设我有一个有序的点列表,围绕一个中心点排列。

我有一个新点要包含在列表中,但保持围绕中心点的顺时针顺序。

最明显的解决方案是找到中心与新点之间的角度,循环遍历列表,计算每个点与中心之间的角度以找到插入点,但我相信有更好的方法不需要使用三角函数 (Math.atan2)。

我遇到了一个有用的排序算法,它可以使用叉积对中心点周围的点数组进行完美排序,但我不知道如何针对我的问题重新设计:

public class Vector2ClockwiseComparer : IComparer<Vector2>
{
    public Vector2 center;

    public Vector2ClockwiseComparer(Vector2 center)
    {
        this.center = center;
    }

    public int Compare(Vector2 v0, Vector2 v1)
    {
        if (v0.x - center.x >= 0 && v1.x - center.x < 0)
            return 1;
        if (v0.x - center.x < 0 && v1.x - center.x >= 0)
            return -1;

        if (v0.x - center.x == 0 && v1.x - center.x == 0) {
            if (v0.y - center.y >= 0 || v1.y - center.y >= 0)
                if (v0.y > v1.y)
                    return 1;
                else return -1;
            if (v1.y > v0.y)
                return 1;
            else return -1;
        }

        // compute the cross product of vectors (CenterPoint -> a) x (CenterPoint -> b)
        var det = (v0.x - center.x) * (v1.y - center.y) -
                            (v1.x - center.x) * (v0.y - center.y);
        if (det < 0)
            return 1;
        if (det > 0)
            return -1;

        // points a and b are on the same line from the CenterPoint
        // check which point is closer to the CenterPoint
        var d1 = (v0.x - center.x) * (v0.x - center.x) +
                        (v0.y - center.y) * (v0.y - center.y);
        var d2 = (v1.x - center.x) * (v1.x - center.x) +
                        (v1.y - center.y) * (v1.y - center.y);
        if (d1 > d2)
            return 1;
        else return -1;
    }
}

另一种可视化问题的方法是将列表中的循环想象为连续的点对,并询问新点是否位于由这两个点和中心点(眼睛)形成的无限平截头体的视线中,但是没有三角函数可以做到吗?

【问题讨论】:

  • 您可以使用此比较器通过二分搜索查找插入索引,就像通常使用标量一样。 Atan 对于这个问题来说绝对是矫枉过正。

标签: list sorting geometry trigonometry


【解决方案1】:

您可以使用基于叉积的CCW(逆时针/顺时针方向)功能(您已经有det)并实现一种二分查找。

我认为避免循环问题的最简单方法是引入两个虚构点 P[M] - P[0] 对中心的镜像和 P[N+1] - 列表末尾第一个点的副本.插入一次并在需要时更正 M 索引。

为第一个和新点查找 CCW。如果为True,则在0..M范围内进行二分查找,并在插入增量M后进行。如果为False,则在M..N+1范围内进行二分查找

【讨论】:

  • 解决方案比这更复杂,因为循环几何。
猜你喜欢
  • 1970-01-01
  • 2011-10-24
  • 1970-01-01
  • 2013-05-20
  • 1970-01-01
  • 2010-09-19
  • 2017-05-25
  • 1970-01-01
  • 2012-08-09
相关资源
最近更新 更多