<p>两球碰撞当且仅当球心距离平方小于等于半径之和的平方,即 dist_sq <= (r1 + r2) * (r1 + r2),需引入 EPS 避免浮点误差,且应直接比较平方量以提升性能与稳定性。</p>

怎么算两个球心距离
判断球体关系的核心是球心距离与半径之和、半径之差的比较。先拿到两个球的中心坐标 center1 和 center2(比如 std::array<double></double> 或自定义结构体),再用欧氏距离公式算平方距离,避免开方——既快又稳:
double dx = center1[0] - center2[0]; double dy = center1[1] - center2[1]; double dz = center1[2] - center2[2]; double dist_sq = dx*dx + dy*dy + dz*dz;
注意:永远优先比较 dist_sq 和半径的平方,而不是调用 sqrt()。浮点误差小、性能高,且能规避 sqrt(-0.0) 等边界问题。
碰撞(相交)的判定条件是什么
两球发生碰撞(即有重叠区域,含相切)当且仅当球心距离 ≤ 半径之和。用平方形式写就是:
double r1 = sphere1.radius; double r2 = sphere2.radius; bool is_colliding = dist_sq <= (r1 + r2) * (r1 + r2);
常见错误:
立即学习“C++免费学习笔记(深入)”;
- 误用
<而非<=,导致相切时判定为“未碰撞” - 把
r1 + r2平方写成r1*r1 + r2*r2,漏掉交叉项 - 没处理
r1或r2为负数的情况(应提前校验半径非负)
怎么判断一个球完全包含另一个球
球 A 包含球 B(B 完全在 A 内部,含内切)的充要条件是:球心距 + B 的半径 ≤ A 的半径。注意方向性——不是对称关系:
// sphere1 是否包含 sphere2? bool contains = dist_sq <= (r1 - r2) * (r1 - r2) && r1 >= r2;
关键点:
- 必须加
r1 >= r2判断,否则当r1 < r2时,(r1 - r2)²仍为正,会导致误判 - 等号成立时是内切,属于包含;若要求“严格内部”,改用
<并去掉等号 - 不要用
dist_sq + r2*r2 <= r1*r1—— 数学等价但易溢出,尤其当半径很大时
要不要考虑浮点精度问题
实际工程中必须考虑。哪怕只差一个 ulp,也可能让相切变成“略分离”或“略穿透”。建议引入小阈值 EPS:
constexpr double EPS = 1e-9; bool is_colliding = dist_sq <= (r1 + r2) * (r1 + r2) + EPS; bool contains = r1 >= r2 && dist_sq <= (r1 - r2) * (r1 - r2) + EPS;
但 EPS 不是越大越好:设太大可能把本不接触的球判为碰撞;设太小则起不到修正作用。典型场景下 1e-9 对 double 坐标足够,若坐标量级达 1e6 以上,需按比例放大 EPS(例如 1e-3)。没有银弹,得看你的数据范围。


















