原文:http://www.cnblogs.com/lujiacheng/archive/2011/07/28/2119636.html

题目: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

 

代码:

#include<stdio.h>

struct node
{
double x,y;
}start[101],end[101];

double direction(node p1,node p2,node p)
{
return (p1.x-p.x)*(p2.y-p.y)-(p1.y-p.y)*(p2.x-p.x);
}

bool is_on_segment(node p1,node p2,node p)
{
double min,max;
if(p1.x<p2.x)
{
min=p1.x;
max=p2.x;
}
else
{
min=p2.x;
max=p1.x;
}
if(p.x>=min&&p.x<=max)
return 1;
return 0;
}

bool intersect_segment(node p1,node p2,node p3,node p4)
{
double d1=direction(p1,p2,p3);
double d2=direction(p1,p2,p4);
double d3=direction(p3,p4,p1);
double d4=direction(p3,p4,p2);
if(d1*d2<0&&d3*d4<0)
return 1;
if(d1==0&&is_on_segment(p1,p2,p3))//去掉on_segment可以判断线段是否与直线相交
return 1;
if(d2==0&&is_on_segment(p1,p2,p4))
return 1;
if(d3==0&&is_on_segment(p3,p4,p1))
return 1;
if(d4==0&&is_on_segment(p3,p4,p2))
return 1;
return 0;
}

int main()
{
int i,j,num,n;
while(scanf("%d",&n)!=EOF&&n)
{
for(i=0;i<n;i++)
{
scanf("%lf%lf%lf%lf",&start[i].x,&start[i].y,&end[i].x,&end[i].y);
}
num=0;
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(intersect_segment(start[i],end[i],start[j],end[j]))
{
num++;
}
}
}
printf("%d\n",num);
}
return 0;
}

posted on 2012-03-19 17:24  煙雨默嘫  阅读(173)  评论(0编辑  收藏  举报