线段求交算法对比研究
-----by wangsh
一.介绍
线段求交算法在计算几何,地理信息系统算法等相关应用中占有重要的位置,本文简单给出算法说明。
Bentley & Ottmann于1979率先提出了基于扫描线的算法,它需要O((n+I)logn)的时间复杂度以及O(n+I)的空间复杂度,而离理论上最优的时间复杂度是O(nlogn)。于是在1992年,Chazelle & Edelsbrunner提出了一个O (nlogn+I)的最优算法,但该算法实现困难,同时仍需要O(n+I)的空间。紧接着Balaban在 1995提出了一个基于分治的算法,该算法的不仅在时间复杂度上是最优的,同时它的空间复杂度只有O(n)。参考参考文献1。目前二维直线相交的最优算法是Balaban提出的分治算法,而比较简单实用的是Bentley & Ottmann的扫描线算法。参考文献2。
参考文献3给出了扫描线算法,有伪代码和Java应用演示,想要了解扫面线的具体计算流程可参考4,另外简单的版本见维基百科(参考文献5)
二.简单说明与源码展示
首先给出两条线段求交的简单算法(如图所示):
C++ Code
Point* intersection(Point p1, Point p2, Point p3, Point p4)
{
// Store the values for fast access and easy
// equations-to-code conversion
float x1 = p1.x, x2 = p2.x, x3 = p3.x, x4 = p4.x;
float y1 = p1.y, y2 = p2.y, y3 = p3.y, y4 = p4.y;
float d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
// If d is zero, there is no intersection
if (d == 0) return NULL;
// Get the x and y
float pre = (x1*y2 - y1*x2), post = (x3*y4 - y3*x4);
float x = ( pre * (x3 - x4) - (x1 - x2) * post ) / d;
float y = ( pre * (y3 - y4) - (y1 - y2) * post ) / d;
// Check if the x and y coordinates are within both lines
if ( x < min(x1, x2) || x > max(x1, x2) ||
x < min(x3, x4) || x > max(x3, x4) ) return NULL;
if ( y < min(y1, y2) || y > max(y1, y2) ||
y < min(y3, y4) || y > max(y3, y4) ) return NULL;
// Return the point of intersection
Point* ret = new Point();
ret->x = x;
ret->y = y;
return ret;
}
下面的代码是
Scott给出的号称Fast 2D Line Intersection Algorithm的算法(参考文献11):
void Intersect_Lines(float x0,float y0,float x1,float y1,
float x2,float y2,float x3,float y3,
float *xi,float *yi)
{
// this function computes the intersection of the sent lines
// and returns the intersection point, note that the function assumes
// the lines intersect. the function can handle vertical as well
// as horizontal lines. note the function isn't very clever, it simply
//applies the math, but we don't need speed since this is a
//pre-processing step
float a1,b1,c1, // constants of linear equations
a2,b2,c2,
det_inv, // the inverse of the determinant of the coefficient
matrix
m1,m2; // the slopes of each line
// compute slopes, note the cludge for infinity, however, this will
// be close enough
if ((x1-x0)!=0)
m1 = (y1-y0)/(x1-x0);
else
m1 = (float)1e+10; // close enough to infinity
if ((x3-x2)!=0)
m2 = (y3-y2)/(x3-x2);
else
m2 = (float)1e+10; // close enough to infinity
// compute constants
a1 = m1;
a2 = m2;
b1 = -1;
b2 = -1;
c1 = (y0-m1*x0);
c2 = (y2-m2*x2);
// compute the inverse of the determinate
det_inv = 1/(a1*b2 - a2*b1);
// use Kramers rule to compute xi and yi
*xi=((b1*c2 - b2*c1)*det_inv);
*yi=((a2*c1 - a1*c2)*det_inv);
} // end Intersect_Lines
上面两个算法在笔者看来,都有缺陷(没有判断没有相交),比较实用的方法首先进行跨立实验进行判断,去除可能不相交等情形。
以后给出笔者的版本(后面补上):
下面给出Wei Qian给出的Segment Intersection的伪代码:
Algorithm FINDINTERSECTIONS(S)
Input. A set of line segments in the plane.
Output. The set of intersection points among the segments in S.
HANDLEENENTPOINT(p)
FINDNEWEVNET(su, sl , p)
这个算法FINDINTERSECTIONS的复杂度是O(nlogn + Ilogn), 其中I是n条线段的交点的个数。
采用这个算法的主要应用为LEDA(见参考文献16)和cairo(见源码中的cairo-bentley-ottmann.c文件)。
参考文献给出了Red and Blue Line Segment Intersections的算法描述,并且给出了算法的Demo。
三.参考文献
a) 清华大学计算几何实验:Balaban线段求交算法http://learn.tsinghua.edu.cn:8080/2008210718/index.htm
b) 2009 英特尔线程挑战赛参赛随笔系列第六题线段求交 http://software.intel.com/zh-cn/blogs/2009/07/08/400002053/
c) 扫描线算法 http://www.lems.brown.edu/~wq/projects/cs252.html
d) 扫描线算法的详细介绍 http://softsurfer.com/Archive/algorithm_0108/algorithm_0108.htm
e) 扫描线算法介绍 http://en.wikipedia.org/wiki/Sweep_line_algorithm
f) Cohen-Sutherland线段裁减的改进算法 http://hi.baidu.com/geochenyj/blog/item/65c4ab1b086e21fdaf5133c8.html
g) 线段的裁剪 http://jpkc.lit.edu.cn/09/jsjtxx/zxjx/3-2-a.htm
h) 红蓝扫描线方法Demo http://www.cs.unc.edu/~snoeyink/demos/rbseg/index.html
i) 高等演算计算几何 http://irw.ncut.edu.tw/peterju/algorithm.html
j) 计算几何简介 http://people.ofset.org/~ckhung/b/cg/intro.php
k) Scott给出的简单求两线求交http://www.gamedev.net/reference/articles/article423.asp
l) 简单演示 http://flassari.is/2008/11/line-line-intersection-in-cplusplus/
m) 两条线段求交点 http://alienryderflex.com/intersect/
n) Matlab求交点方法 http://mathworld.wolfram.com/Line-LineIntersection.html
o) 并行优化线段求交问题 http://itknowledgehub.com/development-integration/parallelization-and-optimization-of-the-line-segment-intersection-problem/
p) LEDA Library of Efficient Data types and Algorithms www.algorithmic-solutions.com/leda
转载请标注:http://blog.csdn.net/wsh6759/article/details/5738426