sat是分离轴定理,用于凸多边形碰撞检测:若存在一轴使两多边形投影不重叠,则无碰撞;否则相交。它适用于任意凸多边形(含不规则形状),但不适用于凹多边形,后者需先三角剖分或转为凸包组合。

什么是SAT,它为什么能用于不规则多边形碰撞检测
SAT(Separating Axis Theorem,分离轴定理)不是C++内置功能,而是一种几何判定逻辑:两个凸多边形不相交 ⇔ 存在一条直线(分离轴),使得两多边形在该轴上的投影不重叠。注意——它只对凸多边形严格成立。如果你的“不规则多边形”是凹的,直接套SAT会漏判或误判。
常见错误现象:std::vector<point></point> 表示的任意多边形直接丢进SAT函数,结果在凹点附近返回 false(误判为无碰撞)。
- 必须先判断输入是否为凸多边形(可用叉积符号一致性检查)
- 若为凹多边形,需先做三角剖分(如ear clipping)或转为凸包组合(如使用Boost.Geometry的
bg::convex_hull) - SAT本身不关心坐标系或精度模型,但浮点比较必须用容差(如
abs(a - b) )
如何提取SAT所需的候选分离轴
对两个凸多边形 A 和 B,只需检查每条边的法向量(垂直方向)作为潜在分离轴。边数分别为 n 和 m,最多检查 n + m 个轴。
关键细节:法向量要单位化吗?不需要——投影长度正比于点积绝对值,方向一致即可;单位化反而引入额外开方误差。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 对A的每条边
v = p[i+1] - p[i],取法向量axis = Point(-v.y, v.x) - 对B同理,注意所有轴应归一化方向(比如统一让x≥0,或强制
axis.x > 0 || (axis.x == 0 && axis.y > 0)避免重复) - 若多边形含共线点,边向量为零向量,跳过该边(否则
axis为零向量,点积全为0,投影坍缩)
如何高效计算投影区间并判断重叠
对每个轴 axis,分别计算多边形所有顶点在该轴上的标量投影(即点积),取最小/最大值得到区间 [minA, maxA] 和 [minB, maxB]。重叠条件是:maxA >= minB && maxB >= minA。
常见性能坑:std::minmax_element 每次遍历都要走一遍,不如手写单循环一次完成;若顶点数少(如四边形),展开循环更优。
- 投影计算用
dot(p, axis),别用norm(axis)归一化后再乘——纯浪费 - 比较时用
maxA 判断分离(比“重叠条件取反”更稳定) - 一旦找到一个分离轴,立刻返回
false(无碰撞),不必检查剩余轴
C++实现时容易被忽略的边界情况
真实场景中,SAT失败往往不是算法错,而是数据预处理没到位。比如:顶点顺序混乱(顺/逆时针混用)、坐标溢出、退化多边形(三点共线)、浮点NaN传播。
- 确保所有多边形顶点按一致顺序(如逆时针)排列,否则法向量方向翻转,投影区间可能颠倒
- 传入前检查顶点数:
if (poly.size() - 若用
double坐标但输入含inf或nan,点积结果不可靠,建议加std::isfinite(p.x) && std::isfinite(p.y)断言 - 当两多边形完全重合或一个完全在另一个内部时,所有轴都重叠——这是正确行为,不代表bug
凹多边形不能跳过分解步骤,哪怕看起来“差不多凸”——只要有一个内角 > 180°,SAT就不可靠。这点最容易被忽略,也最难调试。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










