计算几何-线段相交

快速排斥:不能处理端点为交点的情况;

快速排斥原理:用给出的两条线段作为各自的对角线建立矩形,如果矩形不相交,那么线段一定不相交。

具体实现:假设第一条线段的两个端点分别为(p1,p2)(p3,p4);

if(
min(p1.x,p2.x) <= max(p3.x,p4.x)&&
min(p3.x,p4.x) <= max(p1.x,p2.x)&&
min(p1.y,p2.y) <= max(p3.y,p4.y)&&
min(p3.y,p4.y) <= max(p1.y,p2.y)
) return true;

else return false;

缺点:无法处理下图的情况

《计算几何--快速排斥实验与跨立实验》

-----------------------------------------------------------------------------------------------

 

跨立实验:为了弥补快速排斥的不能处理端点的问题,跨立实验出现。

原理:如果两条线段相互跨过,那么任意一条直线的连个端点一定会出现在另一条线段的两侧,利用叉乘分别判断两条线段就可以了

叉乘: k = x1 * y2 – x2 * y1 ,

if(k>0) {x 在 y 的顺时针方向} 

if(k<0){x 在 y 的逆时针方向}

 

判断跨越:

四个Point类 p1,p2与q1,q2;

如果满足:((p1-q1)×(q2-q1))*((q2-q1)×(p2-q1)) >  0 &&  ((q1-p1)×(p2-p1))*((p2-p1)×(q2-p1)) >  0 

那么这两条线段就是相交的;

上面的式子前面一个是判断p1,p2是不是分布在q1,q2的两侧,第二个则是判断q1,q2是不是分布在p1,p2的两侧;

模板

int segcross(Point a, Point b, Point c, Point d, Point &p)    //判断线段相交
{
    double s1, s2, s3,s4;
    int d1, d2, d3, d4;
    d1=dblcmp(s1=xmult(a,b,c));
    d2=dblcmp(s2=xmult(a,b,d));
    d3=dblcmp(s3=xmult(c,d,a));
    d4=dblcmp(s4=xmult(c,d,b));

    //若规范相交则求交点的代码
    //d1^d2==-2相当于d1*d2<0;
    //跨立实验
    if ((d1^d2)==-2 && (d3^d4)==-2)    //"(d1^d2)"这个小括号是必须的,否则会错
    {
        p.x=(c.x*s2-d.x*s1)/(s2-s1);
        p.y=(c.y*s2-d.y*s1)/(s2-s1);
        return 1;    
    }

    //判断非规范相交
    //d1==0, 则证明a,b,c三点共线; 
    //如果dblcmp(dmult(c,a,b))<0, 则说明点c在点a,b的中间;
    //如果dblcmp(dmult(c,a,b))==0,则说明点c与线段ab的端点a,或者b重合。
    //如果dblcmp(dmult(c,a,b))==0,则说明点c在线段ab的外面。
    if (d1==0 && dblcmp(dmult(c,a,b))<=0 ||
        d2==0 && dblcmp(dmult(d,a,b))<=0 ||
        d3==0 && dblcmp(dmult(a,c,d))<=0 ||
        d4==0 && dblcmp(dmult(b,c,d))<=0)
    {
        return 2;    
    }
    return 0;
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值