线段求交算法对比研究

来源:互联网 发布:java学生成绩总分排序 编辑:程序博客网 时间:2024/05/16 17:38

                                                                                                 线段求交算法对比研究

-----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(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.

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

HANDLEENENTPOINT(p)

  1. 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.
  2. Search inT for the set C(p) of all segments that contain p in theirinterior.
  3. ifL(p)UR(p)UC(p) contains more than one segments
  4.    then Report p an an intersection point.
  5. Delete the segments inR(p)UC(p) from T.
  6. 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.
  7. ifL(p)UC(p) = 0
  8.     then Let su and sl be the upper and lower neighbors ofp in T.
  9.              FINDNEWEVNET(su,sl , p).
  10.     else Let s' be the uppermost segment of L(p)UC(p)in T.
  11.               Letsu be the upper neighbor of s' in T.
  12.              FINDNEWEVNET(sl,s', p).
  13.               Lets" be the lowest segment of L(p)UC(p) in T.
  14.               Letsl be the lower neighbor of s" in T.
  15.              FINDNEWEVNET(sl , s", p).

FINDNEWEVNET(su,sl , p)

  1. ifsu ands 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
  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)       红蓝扫描线方法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