题目:http://www.cnblogs.com/lujiacheng/admin/EditPosts.aspx?opt=1

给了n条线段,求有几个交点,重复的也要算。

判断两线段是否相交:

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

  (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 一个挺好的网站

向量的运算:

向量:u=(u1,u2,u3) v=(v1,v2,v3)

叉积公式:u x v = (u2v3-v2u3 , u3v1-v3u1 , u1v2-u2v1 )

点积公式:u * v = u1v1+u2v2+u3v3

以上是三维的,二维的是u = (u1,u2)    v=(v1,v2)

叉积公式:u x v = u1v2 - u2v1

点积公式: u * v = u1v1+u2v2

代码:

View Code
 1 #include<stdio.h>
2
3 struct node
4 {
5 double x,y;
6 }start[101],end[101];
7
8 double direction(node p1,node p2,node p)
9 {
10 return (p1.x-p.x)*(p2.y-p.y)-(p1.y-p.y)*(p2.x-p.x);
11 }
12
13 bool is_on_segment(node p1,node p2,node p)
14 {
15 double min,max;
16 if(p1.x<p2.x)
17 {
18 min=p1.x;
19 max=p2.x;
20 }
21 else
22 {
23 min=p2.x;
24 max=p1.x;
25 }
26 if(p.x>=min&&p.x<=max)
27 return 1;
28 return 0;
29 }
30
31 bool intersect_segment(node p1,node p2,node p3,node p4)
32 {
33 double d1=direction(p1,p2,p3);
34 double d2=direction(p1,p2,p4);
35 double d3=direction(p3,p4,p1);
36 double d4=direction(p3,p4,p2);
37 if(d1*d2<0&&d3*d4<0)
38 return 1;
39 if(d1==0&&is_on_segment(p1,p2,p3))//去掉on_segment可以判断线段是否与直线相交
40 return 1;
41 if(d2==0&&is_on_segment(p1,p2,p4))
42 return 1;
43 if(d3==0&&is_on_segment(p3,p4,p1))
44 return 1;
45 if(d4==0&&is_on_segment(p3,p4,p2))
46 return 1;
47 return 0;
48 }
49
50 int main()
51 {
52 int i,j,num,n;
53 while(scanf("%d",&n)!=EOF&&n)
54 {
55 for(i=0;i<n;i++)
56 {
57 scanf("%lf%lf%lf%lf",&start[i].x,&start[i].y,&end[i].x,&end[i].y);
58 }
59 num=0;
60 for(i=0;i<n;i++)
61 {
62 for(j=i+1;j<n;j++)
63 {
64 if(intersect_segment(start[i],end[i],start[j],end[j]))
65 {
66 num++;
67 }
68 }
69 }
70 printf("%d\n",num);
71 }
72 return 0;
73 }

  

 posted on 2011-07-28 15:50  渲染独白  阅读(218)  评论(1编辑  收藏  举报