线段求交算法对比研究

                                                                                                  线段求交算法对比研究

-----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 suand 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

 

你可能感兴趣的:(GIS相关)