我有一条折线,以一组有序的(X,Y)坐标给出,可以跨越自身形成一个或多个循环。由此,我想提取一个已删除循环的多边形,其中包括该线与自身交叉的交点。我目前有一个粗暴的蛮力算法,其工作原理如下;
int RemoveLoops(CoordType Points[],int NoPoints)
{
int n = 0; // Start of first line segment
int m = 2; // Offset to n of second line segment
int p = NoPoints;
while (n + m + 1 < p)
{
CoordType Ip; // Intersection point
if (Intersect(Points[n],Points[n+1],Points[n+m],Points[n+m+1],Ip)))
{
Points[n+1] = Ip;
int d = m - 1; // Number of points to delete
for (int i = n + m + 1; i < p; i++)
Points[i - d] = Points[i];
p -= d;
m = 2;
continue; // Restart from intersection point
}
m ++;
if (n + m + 1 >= p) // Reached end of line, change starting segment
{
m = 2; // Reset offset
n++; // Increment starting segment
}
}
return(p); // Return the number of points in the new poly line
}
虽然我对上述内容进行了一些优化,例如通过计算连续线段之间的累积角度,我们知道在我们经过360度之前我们不能碰到一个交叉点,算法仍然是一个非常可怕的O(n ^ 2)。我知道我可以做得比这更好,例如使用set of all intersecting line segments例程作为起点。鉴于已经订购了积分,我认为我应该能做得更好。请注意,上述版本可以正常工作,并返回剩余点数,这很方便但不是必需的。
关于上述优秀算法的任何想法,O(n log n)或更好?
答案 0 :(得分:0)
尝试使用sweep line algorithm方法。直觉上,最好以图形方式考虑算法。您将点放在平面中并从左到右“扫过”它们。在清扫时,您对已经发现的线条的状态保持不变。如果两条线之间存在交叉,则必须在我们已经“发现”的两条线之间发生。从技术上讲,你不必“扫描”飞机:你可以在每次偶然发现一个点时检查不变量。因此,您可以按x
坐标对点进行排序,然后逐个查看。
算法的瓶颈是可以在O(nlogn)
中完成的排序。我很确定你不能比nlog n
做得更好,因为这些类型的问题通常可以归结为排序。您可以将此问题减少到找到一组点的凸包,这也不可能在n log n
以内。
答案 1 :(得分:0)
导致加速或更好算法的通常假设是多边形链是简单的或凸的。一开始,你的连锁店都没有。
可能有一个增量数据结构可以进行O(log n + s)线简单多边形链交叉测试,但我怀疑即使它存在,它也会比仅仅进行分段交叉更复杂并且可能更慢。 / p>