线段求交算法对比研究

                                                                                                  线段求交算法对比研究

-----by wangsh 

一.介绍

线段求交算法在计算几何,地理信息系统算法等相关应用中占有重要的位置,本文简单给出算法说明。

Bentley & Ottmann1979率先提出了基于扫描线的算法,它需要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.

  1. Initialize an empty event queue Q. Next, insert the segment endpoints into Q; each endpoint stores the segments begin from and/or end at itself.
  2. Initialize an empty status structure T.
  3. While Q is not empty
  4. do Determine the next event point p in Q and delete it.
  5.     HANDLEENENTPOINT(p).

HANDLEENENTPOINT(p)

  1. Let L(p) be the set of segments whose left endpoint is p, and R(p) the segments whose right endpoint is p. For vertical segment, the upper endpoint is defined as the left one.
  2. Search in T for the set C(p) of all segments that contain p in their interior.
  3. if L(p)UR(p)UC(p) contains more than one segments
  4.     then Report p an an intersection point.
  5. Delete the segments in R(p)UC(p) from T.
  6. Insert the segments in L(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 to p. If there is a vertical segment, it comes last among all segments containing p.
  7. if L(p)UC(p) = 0
  8.      then Let su and sl be the upper and lower neighbors of p in T.
  9.               FINDNEWEVNET(su, sl , p).
  10.      else Let s' be the uppermost segment of L(p)UC(p) in T.
  11.               Let su be the upper neighbor of s' in T.
  12.               FINDNEWEVNET(sl, s', p).
  13.               Let s" be the lowest segment of L(p)UC(p) in T.
  14.               Let sl be the lower neighbor of s" in T.
  15.               FINDNEWEVNET(sl , s", p).

FINDNEWEVNET(su, sl , p)

  1. if su and s intersect to the right of the sweep line, or on it and below the current event point, and the intersection is not yet present as an event in Q
  2.      then Insert the intersection point as an event into Q.

这个算法FINDINTERSECTIONS的复杂度是O(nlogn + Ilogn), 其中In条线段的交点的个数。

 

采用这个算法的主要应用为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)         CohenSutherland线段裁减的改进算法 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

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 巴拉班算法(Balaban's intersection algorithm)是一种用于解两条二次曲线(可能是椭圆、抛物线或双曲线)的点的算法。该算法的原理是将两条曲线表示为参数方程式,并将它们代入一个多项式方程中,然后解该多项式方程得到点。 该算法的优点是精度高,对于不同类型的曲线都适用,但是计算量较大。在实际应用中,该算法常被用于计算机辅助设计、计算机图形学等领域。 ### 回答2: 巴拉班算法(Balaban's Intersection Algorithm)是一种用于计算平面上两条直线段是否相算法。该算法由美国计算机科学家曼弗雷德·雷文巴拉班(Manfred Rayner Balaban)在1971年提出。 该算法的基本思想是利用了直线段分别由起点和终点表示的特点。对于两条线段AB和CD,如果它们相,则它们的端点依次出现在对方线段的两侧。也就是说,A和B分别在CD线段的两侧,而C和D分别在AB线段的两侧。 算法的步骤如下: 1. 检查线段AB的起点和终点是否在线段CD的两侧。如果是,则它们相。 2. 检查线段CD的起点和终点是否在线段AB的两侧。如果是,则它们相。 3. 如果上述两个条件都不满足,则两条线段不相。 需要注意的是,如果线段的起点和终点重合,那么它们不被认为是相的。此外,该算法只适用于平面上的直线段,不适用于曲线或其他形状。 巴拉班算法的时间复杂度较低,可以在线性时间内完成计算。因此,它在计算几何学和计算机图形学等领域得到广泛应用。 ### 回答3: Balaban算法是一种计算两个多边形之间点的方法。该算法的基本思想是通过遍历多边形的边来找到点。 具体步骤如下: 1. 遍历第一个多边形的边,记当前边为(p1, p2)。 2. 对于第二个多边形的每一条边(q1, q2),计算两条直线的点。 3. 判断该点是否在两条边的点之间,若是则记录该点。 4. 将该边的终点设为起点,继续遍历第一个多边形的下一条边。 5. 返回点的列表。 Balaban算法的时间复杂度为O(nm),其中n和m分别为两个多边形的边数。该算法的优点是简单易实现,适用于计算一般情况下的多边形点。然而,对于特殊情况,例如重叠部分或内含关系的多边形,该算法可能无法得到正确的结果。 总之,Balaban算法是一种计算两个多边形之间点的方法,通过遍历多边形的边来找到点。根据具体情况选择使用该算法进行计算。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值