快速排斥实验和跨立实验

矢量运算与几何判断

矢量

     如果一条线段的端点是有次序之分的话,那么这种线段就称为 有向线段,如果有向线段p1p2的起点p1在坐标的原点,则可以把它称为矢量p2

矢量的加减

     设二维矢量 P = (x1, y1), Q = (x2, y2),则 P + Q = (x1 + x2, y1 + y2), P -Q = (x1 - x2, y1 - y2),且有 P + Q = Q + P, P - Q = -(Q - P)

矢量叉积

     设矢量 P = (x1, y1), Q = (x2, y2),则 P * Q = x1 * y2 - x2 * y1; 其结果是一个由(0, 0), P, Q, P + Q 所组成的平行四边形的 带符号的面积,P * Q = -(Q * P), P * (- Q) =-(P * Q)

     叉积的一个非常重要的性质是可以通过它的符号来判断两矢量相互之间的顺逆时针关系:

           若 P * Q > 0,则 P 在 Q 的顺时针方向

           若 P * Q < 0, 则 P 在 Q 的逆时针方向

           若 P * Q = 0,则 P 与 Q 共线,但不确定 P, Q 的方向是否相同

折线段的拐向判断

     如图,假设有折线段 p0p1p2 ,要确定 p1p2 相对于 p0p1 是向左拐还是向右拐,可以通过计算(p2 - p0)*(p1 -p0) 的符号来确定折线的拐向(点 p2 - p0 实际上就是向量 p2,但这里要注意线段和矢量的区别)


判断点是否在线段上

     设点 Q = (x, y), P1 = (x1, y1), P2 = (x2, y2),若 (Q - P1)*(P2 - P1) =0 且 min(x1, x2) <= x <= max(x1, x2) && min(y1, y2)<= y <= max(y1, y2),则点 Q 在线段 P1P2 上

判断两线段是否相交
1)快速排斥试验

     设以线段 P1P2 为对角线的矩形为 R,设以线段 Q1Q2 为对角线的矩形为 T,若 R、T 不相交,则两线段不可能相交

     假设 P1 = (x1, y1), P2 = (x2, y2), Q1 = (x3, y3), Q2 = (x4, y4),设矩形 R的 x 坐标的最小边界为 minRX = min(x1, x2),以此类推,将矩形表示为 R = (minRX, minRY,maxRX, maxRY) 的形式,若两矩形相交,则相交的部分构成了一个新的矩形 F,如图所示,我们可以知道 F 的 minFX =max(minRX, minTX), minFY = max(minRY, minTY), maxFX = min(maxRX,maxTX), maxFY = min(maxRY, maxTX),得到 F 的各个值之后,只要判断矩形 F 是否成立就知道 R 和T 到底有没有相交了,若 minFX > maxFX 或 minFY > maxFy 则 F 无法构成,RT不相交,否则RT相交


2)跨立试验

     若 P1P2 跨立 Q1Q2,则 P1,P2 分别在 Q1Q2 所在直线的两端,则有 (P1 - Q1)*(Q2 - Q1) *(Q2 - Q1)*(P2 - Q1) > 0,当 (P1 - Q1)*(Q2 - Q1) = 0 时,说明 (P1 - Q1)与 (Q2 - Q1) 共线,但由于已经经过快速排斥试验,所以 Q1 必为 P1P2 与 Q1Q2的交点,依然满足线段相交的条件,则跨立试验可改为:

     当 (P1 - Q1)*(Q2 - Q1) * (Q2 - Q1)*(P2 - Q1) >= 0,则 P1P2 跨立Q1Q2,当 Q1Q2 也跨立 P1P2 的时候,则 P1P2 相交

     (注意式子中被隔开的 * 代表两个叉积的值的相乘,而另外的两个 * 则代表计算矢量叉积)



转自:http://blog.sina.com.cn/s/blog_71dbfe2e0101f7zb.html

<think>判断两条线段是否相交是一个常见的计算几何问题。我们可以通过计算向量叉积的方法来判断。基本思路如下: 1. 快速排斥实验:判断两条线段分别所在的两个矩形是否相交,如果不相交,则线段肯定不相交。 2. 实验:如果两条线段相交,那么每条线段的两端点必然位于另一条线段的两侧(即)。我们可以通过叉积的正负来判断点相对于线段的位置。 具体步骤: 步骤1:快速排斥实验 线段ABCD,分别以ABCD为对角线做矩形,如果这两个矩形不相交,则线段一定不相交。 即满足:max(x1,x2) >= min(x3,x4) and max(x3,x4) >= min(x1,x2) and max(y1,y2) >= min(y3,y4) and max(y3,y4) >= min(y1,y2) 步骤2:实验 如果两条线段相交,则必然满足:点A点B位于线段CD的两侧,并且点C点D位于线段AB的两侧。 判断两点是否在线段的两侧可以通过叉积来实现。 叉积的定义: 向量AB=(x2-x1, y2-y1),向量AC=(x3-x1, y3-y1),则AB×AC = (x2-x1)*(y3-y1) - (y2-y1)*(x3-x1) 叉积的符号可以判断两个向量的相对位置: 如果AB×ACAB×AD的符号相反,则说明CD在线段AB的两侧(即)。 因此,我们需要判断: (向量AB×向量AC) * (向量AB×向量AD) <= 0 且 (向量CD×向量CA) * (向量CD×向量CB) <= 0 注意:由于叉积为0表示共线,这里我们只考虑非共线的情况,但题目要求相交(包括端点相交),所以当叉积等于0时,可能是端点相交,也可能是共线但不相交。 但是,快速排斥实验可以排除大部分共线不相交的情况,而实验中的等于0的情况表示点在线段上(即端点相交或者内部相交)。 然而,严格来说,我们还需要考虑共线但重叠的情况。但根据快速排斥实验实验,当共线且重叠时,快速排斥实验会通过,并且实验中的叉积都为0(乘积为0),所以条件满足。 因此,我们可以这样设计: if 快速排斥实验通过 and (实验1 <=0 and 实验2 <=0): 相交 else: 不相交 注意:实验的两个条件必须同时满足。 下面我们用代码实现。注意:我们假设输入的点是四个点,每个点用(x,y)表示。 但是,有一个特殊情况:当两条线段共线但不相交时,快速排斥实验会判断出它们不相交(因为矩形不相交),所以这种情况不会进入实验。 因此,我们的步骤是: 1. 判断矩形是否相交(快速排斥实验) 2. 同时进行实验(判断两个线段是否互相) 代码实现: 定义函数cross_product,计算向量(p1p2)向量(p1p3)的叉积。 然后分别计算: d1 = cross_product(A, B, C) # 向量AB向量AC的叉积 d2 = cross_product(A, B, D) # 向量AB向量AD的叉积 d3 = cross_product(C, D, A) # 向量CD向量CA的叉积 d4 = cross_product(C, D, B) # 向量CD向量CB的叉积 然后判断:如果d1*d2<=0 且 d3*d4<=0,则相交。 但是,我们还需要先通过快速排斥实验,避免在明显不相交的情况下计算叉积。 因此,整体代码结构如下: if 满足快速排斥实验: 计算d1,d2,d3,d4 if (d1*d2 <= 0) and (d3*d4 <= 0): return True return False 注意:由于浮点数计算可能存在精度问题,但这里我们假设输入是整数,所以用整数运算。 下面我们用Python实现这个函数。</think>要判断线段ABCD是否相交,可以使用计算几何中的**实验****快速排斥实验**。以下是Python实现: ```python def cross_product(x1, y1, x2, y2, x3, y3): """计算向量(x2-x1, y2-y1)向量(x3-x1, y3-y1)的叉积""" return (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1) def is_intersect(A, B, C, D): """ 判断线段ABCD是否相交 :param A: 点A的坐标 (x1, y1) :param B: 点B的坐标 (x2, y2) :param C: 点C的坐标 (x3, y3) :param D: 点D的坐标 (x4, y4) :return: True如果相交,否则False """ x1, y1 = A x2, y2 = B x3, y3 = C x4, y4 = D # 快速排斥实验:检查线段所在矩形是否相交 if max(x1, x2) < min(x3, x4) or max(x3, x4) < min(x1, x2) or \ max(y1, y2) < min(y3, y4) or max(y3, y4) < min(y1, y2): return False # 实验:计算四个叉积 cp1 = cross_product(x1, y1, x2, y2, x3, y3) # AB × AC cp2 = cross_product(x1, y1, x2, y2, x4, y4) # AB × AD cp3 = cross_product(x3, y3, x4, y4, x1, y1) # CD × CA cp4 = cross_product(x3, y3, x4, y4, x2, y2) # CD × CB # 判断叉积符号是否相反(允许端点相交) return (cp1 * cp2 <= 0) and (cp3 * cp4 <= 0) # 测试示例 if __name__ == "__main__": A = (0, 0) B = (2, 2) C = (0, 2) D = (2, 0) print(is_intersect(A, B, C, D)) # 输出:True(相交) A = (0, 0) B = (1, 1) C = (2, 2) D = (3, 3) print(is_intersect(A, B, C, D)) # 输出:False(不相交) ``` ### 代码解释: 1. **叉积计算函数 `cross_product`**: - 计算两个向量的叉积:`(x2-x1)(y3-y1) - (y2-y1)(x3-x1)` - 几何意义:结果的正负表示第三个点相对于前两点连线的位置(顺时针/逆时针) 2. **相交判断函数 `is_intersect`**: - **快速排斥实验**(第13-15行): - 检查两条线段的最小包围矩形是否相交 - 若矩形不相交,则线段必然不相交(快速排除) - **实验**(第18-24行): - 计算四个关键叉积: - `cp1`:点C相对于线段AB的位置 - `cp2`:点D相对于线段AB的位置 - `cp3`:点A相对于线段CD的位置 - `cp4`:点B相对于线段CD的位置 - 若 `(cp1 * cp2 ≤ 0)` 且 `(cp3 * cp4 ≤ 0)`,则线段相交 - 等于0的情况表示端点在另一线段上(视为相交) 3. **测试用例**: - 示例1:线段 `(0,0)-(2,2)` `(0,2)-(2,0)` 相交(输出True) - 示例2:线段 `(0,0)-(1,1)` `(2,2)-(3,3)` 不相交(输出False) ### 算法原理: 1. **快速排斥实验**:通过坐标范围快速排除不可能相交的情况 2. **实验**:利用叉积符号判断两点是否在线段两侧 - 若点CD在线段AB的两侧 **且** 点AB在线段CD的两侧 → 线段相交 - 叉积为0时表示三点共线(需结合快速排斥实验判断是否重叠) ### 特殊情况处理: - **端点相交**:当线段端点落在另一线段上时(叉积=0),算法返回True - **共线不相交**:通过快速排斥实验排除(矩形不相交) - **完全重叠**:算法视为相交(所有叉积为0且矩形相交)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值