SAT分离轴定理仅适用于凸多边形,若为凹多边形需先进行凸分解;其核心是检查两凸多边形在所有边法向量上的投影是否均重叠,全部重叠才判定相交。

什么是SAT分离轴定理的适用前提
SAT(Separating Axis Theorem)只适用于凸多边形。如果你手头是两个不规则多边形,第一步必须确认它们是否都是凸的——否则直接套用SAT会得出错误结论。常见误区是把任意多边形(比如带凹口的L形、星形)直接丢进SAT逻辑里跑,结果明明相交却返回“不相交”。
判断凸性很简单:遍历所有顶点,用叉积检查每条边转向是否一致(全部左转或全部右转)。可以用 cross_product 计算连续三顶点构成的向量叉积符号:
若出现正负混杂,说明存在凹点,该多边形非凸。
如何对凸多边形执行SAT检测
核心思路:如果存在一条直线(即一个轴),能把两个凸多边形完全分开,那它们就不相交;只有所有候选轴上投影都重叠,才判定为相交。
立即学习“C++免费学习笔记(深入)”;
候选轴只来自两个多边形各自的边的法向量(单位化后即可):
- 对每个凸多边形,取每条边向量
v = p[i+1] - p[i],其法向量为normal = (-v.y, v.x)(2D下) - 将两个多边形所有顶点分别投影到该法向量上(点积运算),得到各自投影区间
[min, max] - 检查这两个区间是否重叠:若
projA.max ,则此轴可分离,直接返回 false
注意:法向量无需归一化也能做投影比较,但归一化后数值更稳定;若用浮点数,务必加入小 epsilon(如 1e-6)避免因精度导致误判。
不规则多边形怎么办:分解还是近似
真正的“不规则多边形”大概率是凹的。此时不能跳过预处理:
- 若必须精确判断,需先做**凹多边形三角剖分**(如用 Ear Clipping 或 monotone decomposition),再对每对三角形调用 SAT(或更简单的三角形-三角形相交检测)
- 若允许一定误差且多边形变化不大,可考虑用 **凸包近似**:对每个不规则多边形计算
convex_hull,再用 SAT 判断凸包是否相交;但要注意——凸包相交 ≠ 原多边形相交(假阳性),不相交则原多边形一定不相交(安全) - 更稳妥的做法是用通用多边形相交库,比如 Clipper2 的
Execute+ctIntersection,它内部处理了凹/自交/退化等边界情况
容易被忽略的边界与性能陷阱
SAT本身很快(O(n+m)),但实际落地时几个细节常被绕开:
- 顶点顺序必须一致(全顺时针或全逆时针),否则法向量方向反了,投影区间可能错乱
- 共线边、重复点、极小面积多边形会导致法向量为零向量——必须在取法向量前检查
v.x == 0 && v.y == 0,跳过或报错 - 浮点误差累积:投影比较时别用
==,用abs(a - b) ;区间重叠判断也建议加 eps 宽容 - 若多边形含大量顶点(比如 >100),而你只需要“是否相交”而非“交集形状”,SAT仍是首选;但若后续还要计算交点坐标,直接上布尔运算更省事
真正麻烦的从来不是SAT公式本身,而是把原始数据洗干净、喂对、再防住浮点和退化——这些地方没处理好,算法再漂亮也返回随机结果。


















