跨立实验判断线段是否相交->POJ3304

来源:互联网 发布:淘宝店铺优惠券花钱么 编辑:程序博客网 时间:2024/05/26 02:20

在二维坐标下介绍一些定义:

点:A(x1,y1),B(x2,y2)
向量:向量AB=( x2 - x1 , y2 - y1 )= ( x , y );
向量的模 |AB| = sqrt ( x*x+y*y );


向量的点积:

向量叉积 结果为 x1*x2 + y1*y2。
点积的结果是一个数值。
点积的集合意义:
我们以向量 a 向向量 b 做垂线,则 | a | * cos(a,b)为 a 在向量 b 上的投影,即点积是一个向量在另一个向量上的投影乘以另一个向量。且满足交换律
应用:
可以根据集合意义求两向量的夹角,cos(a,b) =( 向量a * 向量b ) / (| a | * | b |) = x1*x2 + y1*y2 / (| a | * | b |)

向量的叉积:

向量叉积 结果为 x1*y2-x2*y1
叉积的结果也是一个向量,是垂直于向量a,b所形成的平面,如果看成三维坐标的话是在 z 轴上,上面结果是它的模。

方向判定:

右手定则,(右手半握,大拇指垂直向上,四指右向量a握向b,大拇指的方向就是叉积的方向)

叉积的集合意义:

1:其结果是a和b为相邻边形成平行四边形的面积。
2:结果有正有负,有sin(a,b)可知和其夹角有关,夹角大于180°为负值。
3:叉积不满足交换律

应用:

1:通过结果的正负判断两矢量之间的顺逆时针关系
若 a x b > 0表示a在b的顺时针方向上
若 a x b < 0表示a在b的逆时针方向上
若 a x b == 0表示a在b共线,但不确定方向是否相同

2:判断折线拐向,可转化为判断第三点在前两的形成直线的顺逆时针方向,然后判断拐向。
3:判断一个点在一条直线的那一侧,同样上面的方法。
4:判断点是否在线段上,可利用叉乘首先判断是否共线,然后在判断是否在其上。
5:判断两条直线是否想交(跨立实验)
根据判断点在直线那一侧我们可以判断一个线段的上的两点分别在另一个线段的两侧,当然这是不够的,因为我们画图发现这样只能够让直线想交,而不是线段,所以我们还要对另一条线段也进行相同的判断就ok。

判断两线段是否相交:

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

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


POJ3304

题意:

给出一些线段,求是否存在一条直线,使得这些线段在该直线的投影有共同交点。

题解:

求这样一条直线是否存在,因为这些线段在这条直线的投影有共同交点,即这条直线的垂线和所有线段都有交点,问题即转换成了是否存在一条直线和所有线段相交。
直线可以分别枚举每条线段的两个端点,然后在判断和每个线段是否相交即可。

代码:

#include <stdio.h>#include <iostream>#include <algorithm>#include <cmath>using namespace std ;#define MAX 110const double eps = 1e-8;int sgn(double x){    if(fabs(x) < eps) return 0 ;    if(x < 0) return -1 ;    else return 1 ;}struct Point{    double x , y ;    Point(){}    Point(double _x , double _y)    {        x = _x ; y = _y ;    }    Point operator - (const Point &b) const    {        return Point(x - b.x , y - b.y) ;    }    double operator ^ (const Point &b) const    {        return x*b.y - y*b.x ;    }    double operator * (const Point &b) const    {        return x*b.x + y*b.y ;    }};struct Line{    Point s , e ;    Line(){}    Line(Point _s , Point _e)    {        s = _s ; e = _e ;    }};double xmult(Point p0,Point p1,Point p2) //叉积p0p1 X p0p2{    return (p1-p0)^(p2-p0);}bool Seg_inter_line(Line l1,Line l2) //判断直线l1和线段l2是否相交{    return sgn(xmult(l2.s,l1.s,l1.e))*sgn(xmult(l2.e,l1.s,l1.e)) <= 0;}double dist(Point a,Point b){    return sqrt( (b - a)*(b - a) );}Line line[MAX] ;bool check(Line l1 , int n){    if(sgn(dist(l1.s,l1.e)) == 0) return false ;    for(int i = 0;i < n;i++)        if(Seg_inter_line(l1,line[i]) == false)            return false ;    return true ;}int main(){    int T , n;    scanf("%d" , &T) ;    while(T --)    {        scanf("%d" , &n) ;        double x1,x2,y1,y2 ;        for(int i = 0 ; i < n ; i ++)        {            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);            line[i] = Line(Point(x1,y1),Point(x2,y2));        }        bool flag = false ;        for(int i = 0 ; i < n ; i ++)        {            for(int j = 0 ; j < n ; j ++)            {                if(check(Line(line[i].s,line[j].s),n) || check(Line(line[i].s,line[j].e),n)                        || check(Line(line[i].e,line[j].s),n) || check(Line(line[i].e,line[j].e),n) )                {                    flag = true;                    break;                }            }        }        if(flag) printf("Yes!\n") ;        else printf("No!\n") ;    }    return 0 ;}
0 0
原创粉丝点击