判断两多边形是否相交需同时满足:至少一对边规范相交,或一个完全在另一个内部;核心是用叉积+跨立实验配合包围盒预检的isintersect函数,避免斜率法。

两个多边形是否发生几何相交,不能只靠「有没有顶点在对方内部」来判断——这是最常踩的坑。真正可靠的判断必须同时满足两个条件:至少有一对边相交,或一个完全落在另一个内部(此时也属于相交)。下面分场景给出可直接落地的 C++ 实操路径。
用 isIntersect 检测任意两条边是否规范相交
这是所有判断的基石。不要手写斜率公式(y = kx + b),会除零、浮点溢出、且无法处理垂直线。推荐用叉积+跨立实验,配合包围盒预检:
- 先做快速排斥:若一条线段的
max.xmin.x,直接返回false - 再用
crossProduct(p, a, b)计算三点叉积符号,判断点p在线段ab左/右/共线 - 两条线段
AB与CD相交 ⇔crossProduct(A,C,B) * crossProduct(A,B,D) 且 <code>crossProduct(C,A,D) * crossProduct(C,D,B) ,但注意等号仅允许端点重合时成立;若业务要求「严格内部相交」,应改为 <code> - 端点重合(如
A == C)不算相交,除非你明确需要拓扑意义上的「接触即相交」
凸多边形优先用分离轴定理(SAT)快速否决
对两个凸多边形,SAT 是 O(n+m) 的高效筛法,不相交时能立刻返回 false,避免后续全量边检测:
- 取 A 的每条边的法向量(即旋转 90° 得到的单位向量)作为潜在分离轴
- 对每个轴,计算 A 和 B 所有顶点在该轴上的投影(点积),得到各自的投影区间
[minA, maxA]和[minB, maxB] - 若存在某个轴上
maxA ,则两多边形不相交,直接返回 <code>false - 若所有轴都重叠,SAT 无法确认是否相交,需 fallback 到边相交检测或点包含测试
- 注意:SAT 对凹多边形无效,强行使用会漏判「U 形嵌套矩形」这类典型 case
凹多边形必须双重验证:边相交 + 顶点包含
仅检测边相交会漏掉「完全包含」情形;仅检测顶点又会误判「U 形穿出」——二者缺一不可:
- 遍历 A 的每条边,调用
isIntersect与 B 的每条边比对;任一返回true→ 相交成立 - 若无边相交,再检查:A 的所有顶点是否都在 B 内部?B 的所有顶点是否都在 A 内部?用
point_in_polygon实现 -
point_in_polygon必须用非零环绕数(winding number)算法,而非射线法——后者对自相交或接近退化多边形鲁棒性差 - 浮点比较必须带容差:
abs(x) ,不能写 <code>x == 0 - 若 A 所有顶点在 B 内,且 B 至少一个顶点不在 A 内 → A ⊂ B → 属于相交;反之亦然
实际工程中绕不开的边界与精度陷阱
真实坐标数据几乎总是带来浮点误差和拓扑模糊,硬套理论会崩:
- 顶点落在对方边上(距离
1e-9)算不算相交?业务必须明确定义,然后统一加容差判断,不要混合使用==和 - 多边形顶点顺序不一致(顺/逆时针混用)会导致 winding number 符号翻转,先用
compute_orientation校验并归一化方向 - 共线线段(如两条边部分重叠)需单独处理:用参数化求交并检查交集是否为非零长度线段,不能只依赖端点重合
- 性能敏感场景(如游戏帧内碰撞)建议先跑 AABB 包围盒粗筛:
is_aabb_overlap能干掉 80% 以上无需细判的情况
真正难的不是写对单个函数,而是把「边相交」「点在内」「方向归一」「容差控制」「凸凹分支」这几层逻辑稳稳套在一起——漏掉任意一层,线上就可能在某个特定角度下突然判定失效。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











