想象一下,我有一个有序的点列表,围绕一个中心点排列。
我有一个新点,我想在列表中包含,但保持围绕中心点的顺时针顺序。
最明显的解决方案是找到中心和新点之间的角度,循环遍历列表,计算每个点与中心之间的角度以找到插入点,但我相信有更好的方法并不需要使用三角函数(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;
}
}
另一种可视化问题的方法是想象通过列表循环作为连续的点对,并询问新点是否位于由这两个点和中心点(眼睛)形成的无限截头体的眼线中,但是没有三角法可以做到吗?
答案 0 :(得分:0)
您可以使用基于跨产品的CCW(逆时针/顺时针方向)功能(您已经拥有det
)并实现一种二分搜索。
我认为避免循环问题的最简单方法是引入两个虚拟点P [M] - P [0]对中心的镜像和P [N + 1] - 列表末尾第一个点的副本。插入一次并在需要时更正M索引。
查找第一个和新点的CCW。如果为True,则在范围0..M
中进行二进制搜索,并在插入后增加M.如果为False,则在范围M..N+1
中进行二进制搜索