不简单的【线段求交】

103 篇文章 0 订阅
62 篇文章 0 订阅

一直以来感觉线段求交这种级别的算法很easy,甚至没有专门研究的必要,实际操作过程发现简约不简单,需要考虑各种特殊case。google一些后还是没有满意的结果,有理论的没有code,有code的没有理论甚至怀疑有漏洞。最后融会贯通后给出一个可用的版本:

1. 通过两个线段的包围盒快速拒绝。


2. 处理包围盒相交,但实际线段并不相交的case:

两条线段不相交,当且仅当:一条线段的两个端点全部都在另外一条线段的同一边。通过向量叉乘的符号判断,如下图:


P3、P4点在P1P2直线的同侧,当且仅当:P1P2向量与P2P3,P2P4的向量符号相同。

3. 判断线段相交的充分必要条件

两条线段相交,当且仅当下面每两对的叉乘结果有不同符号(或者每对中的一个为0)


// 叉乘顺时针为负,逆时针为正
S1 = (p1 - p4) x (p3 - p4)	// p4p1 x p4p3	正	p1,p3,p4三角形面积两倍
S2 = (p2 - p4) x (p3 - p4)	// p4p2 x p4p3	负	p2,p3,p4三角形面积两倍
S3 = (p3 - p2) x (p1 - p2)	// p2p3 x p2p1	负 	p1,p2,p3三角形面积两倍
S4 = (p4 - p2) x (p1 - p2)	// p2p4 x p2p1	正	p1,p2,p4三角形面积两倍
根据步骤2中得出S1 * S2 > 0 || S3 * S4 > 0两个线段没有交点,剩余情况则有交点。 (2D中向量叉乘结果正好是一个数值)

4. 计算交点
1)S1==0 表示p1在p3,p4线段上面,p1为交点;
2)S2==0 表示p2在p3,p4线段上面,p2为交点;
3)S3==0 表示p3在p1,p2线段上面,p3为交点;
4)S4==0 表示p4在p1,p2线段上面,p4为交点;
5)最后一种情况S1*S2 < 0 && S3*S4 < 0时,即最为常见的两个线段相互交叉情况,我们需要计算交点坐标。
利用上文已经预计算好叉乘,2D中两个向量叉乘的物理意义是面积,S1的一半等于p1,p3,p4三角形面积。设P1P2与P3P4交点为Q,则Q的坐标为P1、P2的加权平均,P1的权值为t1=P1Q / P1P2;P2的权值为t2=P2Q / P1P2,{ t1+t2 =1 and t1 > 0, t2 > 0 } 。
通过简单的三角形相似原理,可以得出:
t1 = |S1| / (| S1| + |S2|)  => t1 = S1 / (S1 - S2)
t2 = |S2| / (| S1| + |S2|)  => t2 = S2 / (S1 - S2)
最终Q为P1,P2加权平均:
Q.x = P1.x * t1 + P2.x * t2;
Q.y = p1.y * t1 + P2.y * t2



refer:

1.  http://fins.iteye.com/blog/1522259

2. http://www.cppblog.com/wicbnu/archive/2009/08/24/94225.html


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值