点在球体内当且仅当(x−cx)²+(y−cy)²+(z−cz)²≤r²,通过比较平方距离与半径平方避免开方运算,提升效率并减少浮点误差。

判断点是否在球体内:核心是距离比较
直接看球心到点的距离是否小于等于半径。这是最可靠、最高效的方法,不需要任何额外库或几何运算。
关键点在于:三维欧氏距离的平方比开方更快,也避免浮点误差和 sqrt 调用开销。所以实际比较 dx*dx + dy*dy + dz*dz 和 r*r 即可。
- 设球心为
(cx, cy, cz),半径为r,待测点为(x, y, z) - 计算平方距离:
dist_sq = (x - cx)*(x - cx) + (y - cy)*(y - cy) + (z - cz)*(z - cz) - 判断:
dist_sq —— 注意用 <code> 包含球面本身
浮点精度下 == 和 的陷阱
用 float 或 double 表示坐标时,直接用 == 判断是否“刚好在球面上”几乎总会失败。哪怕数学上相等,计算过程中的舍入误差会让 dist_sq 略大于或略小于 r*r。
- 永远不要写
dist_sq == r * r来判断球面 - 若需区分“内部”“表面”“外部”,应引入容差(epsilon):
abs(dist_sq - r*r) 判定表面,<code>dist_sq 判定严格内部 - eps 值取决于坐标量级:对
double且坐标在 [-1000, 1000] 范围,1e-9通常够用;若坐标很大(如 1e6),eps 也要按比例放大
用 std::hypot 会更安全吗?
不会,而且更慢。虽然 std::hypot(x,y,z)(C++17 起支持三参数)能防止中间结果溢出,但球体判断根本不需要真实距离值——只需要和 r 比较,而 r*r 是已知常量。直接算平方和既快又稳定。
立即学习“C++免费学习笔记(深入)”;
-
std::hypot内部做了多步缩放和 sqrt,纯属浪费 - 只有当你必须知道精确距离(比如排序、归一化方向向量),才考虑它
- 若真担心大数溢出(比如坐标达 1e150),应先做坐标归一化或换用更高精度类型,而不是依赖
hypot
封装成函数时要注意什么
别把球体参数硬编码成全局变量,也别每次传 7 个独立参数。推荐用结构体封装球体,并重载 operator() 或写清晰命名的函数。
- 定义:
struct Sphere { double cx, cy, cz, r; }; - 函数签名建议:
bool is_inside(const Sphere& s, double x, double y, double z) - 避免传
const Sphere*—— 指针带来空指针风险,且无必要 - 如果频繁调用(如光线追踪中每像素测试数百次),把
r*r存在Sphere里预计算,省去每次乘法
最易被忽略的是:球体半径为负时行为未定义。实际代码中应加断言或提前返回 false,否则 r*r 仍是正数,逻辑看似正常但语义错误。


















