线段求交算法对比研究
来源:互联网 发布:java学生成绩总分排序 编辑:程序博客网 时间:2024/05/16 17:38
线段求交算法对比研究
-----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(Pointp1, 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):
voidIntersect_Lines(floatx0,floaty0,floatx1,floaty1,
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的伪代码:
AlgorithmFINDINTERSECTIONS(S)
Input. A set of line segments in the plane.
Output. The set of intersection points among the segments in S.
- Initialize an empty event queueQ. Next, insert the segment endpoints into Q; each endpoint stores the segments begin from and/or end at itself.
- Initialize an empty status structureT.
- WhileQ is not empty
- doDetermine the next event point p in Q and delete it.
- HANDLEENENTPOINT(p).
HANDLEENENTPOINT(p)
- LetL(p) be the set of segments whose left endpoint is p, and R(p) the segments whose right endpoint isp. For vertical segment, the upper endpoint is defined as the left one.
- Search inT for the set C(p) of all segments that contain p in theirinterior.
- ifL(p)UR(p)UC(p) contains more than one segments
- then Report p an an intersection point.
- Delete the segments inR(p)UC(p) from T.
- Insert the segments inL(p)UC(p) into T. The order of the segments in T should correspond the the order in which they are intersected by a sweep line just right top. If there is a vertical segment, it comes last among all segments containingp.
- ifL(p)UC(p) = 0
- then Let su and sl be the upper and lower neighbors ofp in T.
- FINDNEWEVNET(su,sl , p).
- else Let s' be the uppermost segment of L(p)UC(p)in T.
- Letsu be the upper neighbor of s' in T.
- FINDNEWEVNET(sl,s', p).
- Lets" be the lowest segment of L(p)UC(p) in T.
- Letsl be the lower neighbor of s" in T.
- FINDNEWEVNET(sl , s", p).
FINDNEWEVNET(su,sl , p)
- ifsu andsl intersect to the right of the sweep line, or on it and below the currentevent point, and the intersection is not yet present as an event in Q
- then Insert the intersection point as an event into Q.
这个算法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) 红蓝扫描线方法Demohttp://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 Algorithmswww.algorithmic-solutions.com/leda
转载请标注:http://blog.csdn.net/wsh6759/article/details/5738426
- 线段求交算法对比研究
- 线段求交算法demo
- poj1127线段求交
- N条线段求交的扫描算法
- 线段与三角形求交
- 不简单的【线段求交】
- 计算几何——线段求交
- poj3304(计算几何+线段求交)
- POJ1408-Fishnet(线段求交)
- hdu 1086 计算几何 线段求交
- HDU 1086 (平面几何 线段求交)
- hdu1255(线段树求面积交)
- 几种插值算法对比研究
- 线段树求周长求交面积的做法
- 2009 英特尔® 线程挑战赛 第六题 线段求交
- HDU1255 求面积交 线段树+离散化
- poj3225(线段树求区间交,并,补)
- (beginer)线段求交:多边形面积 UVA 1301 - Fishnet
- [转] CString、TCHAR*、char*转换
- GLFW 简单入门学习
- 面试求职--IT面试常见问题总结
- 传感器的技术参数
- C#基础篇 重写与重载,以及其中设计的虚方法和抽象方法的使用和区别
- 线段求交算法对比研究
- [转]Mysql源码编译配置相关
- Hibernate get和load区别
- 大家好!
- History管理 MTK
- C#开发音频--WinMM.dll 函数汇总
- 【hnoi2010】弹飞绵羊
- 在SVN中创建pre-revprop-change hook
- 《Linux内核修炼之道》 之 高效学习Linux内核