判断两线段是否相交

转自:http://www.cnblogs.com/dxp498688071/archive/2011/3/2.html

几何题做的很少,以至于一个很简单的题目写了很久

若是判断直线和线段是否有交点,把on_segment去掉就可以了

  判断两线段是否相交:

  我们分两步确定两条线段是否相交:

  (1)快速排斥试验

    设以线段 P1P2 为对角线的矩形为R, 设以线段 Q1Q2 为对角线的矩形为T,如果R和T不相交,显然两线段不会相交。

  (2)跨立试验

    如果两线段相交,则两线段必然相互跨立对方。若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 ) 和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改写成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。所以判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。同理判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。具体情况如下图所示:

    

  在相同的原理下,对此算法的具体的实现细节可能会与此有所不同,除了这种过程外,大家也可以参考《算法导论》上的实现。

关于计算几何算法概述网站 http://dev.gameres.com/Program/Abstract/Geometry.htm 一个挺好的网站

view source print ?
01 #include<stdio.h>
02  
03 struct point
04 {
05     double x,y;
06 };
07  
08 double direction( point p1,point p2,point p )
09 {
10     return ( p1.x -p.x )*( p2.y-p.y) -  ( p2.x -p.x )*( p1.y-p.y)   ;
11 }
12  
13 int on_segment( point p1,point p2 ,point p )
14 {
15     double max=p1.x > p2.x ? p1.x : p2.x ;
16     double min =p1.x < p2.x ? p1.x : p2.x ;
17  
18     if( p.x >=min && p.x <=max )
19         return 1;
20     else
21         return 0;
22 }
23  
24 int segments_intersert( point p1,point p2,point p3,point p4 )
25 {
26     double d1,d2,d3,d4;
27     d1 = direction ( p1,p2,p3 );
28     d2 = direction ( p1,p2,p4 );
29     d3 = direction ( p3,p4,p1 );
30     d4 = direction ( p3,p4,p2 );
31     if( d1*d2<0 && d3*d4<0 )
32         return 1;
33     else if( d1==0 && on_segment( p1,p2,p3 ) )
34         return 1;
35     else if( d2==0 && on_segment( p1,p2,p4 ) )
36         return 1;
37     else if( d3==0 && on_segment( p3,p4,p1 ) )
38         return 1;
39     else if( d4==0 && on_segment( p3,p4,p2 ) )
40         return 1;
41  
42     return 0;
43 }
44  
45 int main()
46 {
47     int n,i,j,num;
48     point begin[105],end[105];
49  
50     whilescanf("%d",&n) && n!=0 )
51     {
52         num=0;
53         for( i=0;i<n;i++)
54         {
55             scanf("%lf %lf %lf %lf",&begin[i].x ,&begin[i].y ,&end[i].x ,&end[i].y );
56         }
57         for( i=0;i<n;i++)
58             for(j=i+1;j<n;j++)
59                 {
60                     if( segments_intersert( begin[i],end[i],begin[j],end[j] ) )
61                         num++;
62                 }
63         printf("%d\n",num);
64     }
65     return 0;
66 }

你可能感兴趣的:(判断两线段是否相交)