"在高维空间的对峙中,任何一个微小的误差,都是背叛。" ------ 几何判定法则的守夜人
🎬 引子:点的身份危机
你站在一块浮空的玻璃平台上,四个奇点漂浮于你周围。他们形成了一个神秘的四面体,而你,站在这四维神庙的边界上,只想知道:
"我,到底是在里面,还是在外面?"
欢迎来到**"点在四面体内判定"**这场计算几何中的永恒哲学问题。
🧱 基础概念:四面体与体积的秘密联结
假设我们有一个四面体,由点 A
, B
, C
, D
构成,我们想判断任意一点 P
是否在这个四面体内部。
🌟 关键点:将四面体拆成四个子四面体,分别包含点 P 和四面体的三角面之一,然后计算它们的有符号体积。
🗣️ 小技巧:体积带符号才有意义,正负符号才是你我之分!
🧮 四个体积的判定逻辑
我们定义如下 4 个体积(每个包含 P 和四面体的一个三角面):
V0 = Volume(P, B, C, D)
V1 = Volume(A, P, C, D)
V2 = Volume(A, B, P, D)
V3 = Volume(A, B, C, P)
若这些体积的符号全部相同(全正或全负) ,则点 P
在四面体内。
否则,P 就像是走错维度的流浪者,被挡在了门外。
⚠️ 共面崩溃的陷阱:浮点地狱中的幽灵
在理想数学世界里,determinant(A, B, C, D)
不会出错。
可在现实世界,JavaScript 的 Number
类型只有 64 位双精度,面对微小的三角形和几乎共面的点时,误差像幽灵一样扰乱真相。
这就可能导致你看到的符号是"错的",从而作出"你其实在里面"的幻觉判断!
🧠 Shewchuk 的魔法:自适应精度几何
Jonathan Shewchuk,是一位几何裁决官。他在 1990s 提出了自适应精度几何谓词(Adaptive Precision Predicates) :
"我们不能消除误差,但可以让它服从我们。"
🧙♂️ 怎么实现?
- 使用多重精度表示数值(如扩展浮点或浮点对)
- 动态判断误差范围,根据需求提升计算精度
- 最终确保 符号的正确性,即你只需知道 "这是正的" 还是 "负的",而不是体积到底是多少。
Shewchuk 说白了就是:"我不求你算得准,只要你判断得对。"
💻 JS 实现:简单版本(理想状态)
ini
function signedVolume(a, b, c, d) {
const ab = [b.x - a.x, b.y - a.y, b.z - a.z];
const ac = [c.x - a.x, c.y - a.y, c.z - a.z];
const ad = [d.x - a.x, d.y - a.y, d.z - a.z];
return (
ab[0] * (ac[1] * ad[2] - ac[2] * ad[1]) -
ab[1] * (ac[0] * ad[2] - ac[2] * ad[0]) +
ab[2] * (ac[0] * ad[1] - ac[1] * ad[0])
);
}
function pointInTetrahedron(p, a, b, c, d) {
const v0 = signedVolume(p, b, c, d);
const v1 = signedVolume(a, p, c, d);
const v2 = signedVolume(a, b, p, d);
const v3 = signedVolume(a, b, c, p);
return (v0 > 0 && v1 > 0 && v2 > 0 && v3 > 0) ||
(v0 < 0 && v1 < 0 && v2 < 0 && v3 < 0);
}
🧪 精度加强:接入 Shewchuk 的判定器(用 npm 包)
安装 Shewchuk 的精度神器:robust-orientation
npm install robust-orientation
然后在 JS 中使用:
ini
import orient3d from 'robust-orientation/3';
function pointInTetrahedron_robust(p, a, b, c, d) {
const o0 = orient3d(p, b, c, d);
const o1 = orient3d(a, p, c, d);
const o2 = orient3d(a, b, p, d);
const o3 = orient3d(a, b, c, p);
const allPositive = o0 > 0 && o1 > 0 && o2 > 0 && o3 > 0;
const allNegative = o0 < 0 && o1 < 0 && o2 < 0 && o3 < 0;
return allPositive || allNegative;
}
📌 注意:
orient3d
返回的是方向(正/负/零),它通过高精度浮点表示,避免因共面、精度抖动导致的误判。
🧙♀️ 总结与箴言
- 判断点是否在四面体内的关键,在于有符号体积;
- 漂亮地计算体积靠行列式 ,而正确判断靠符号;
- 当精度崩坏时,Shewchuk 的自适应精度算法是唯一真理;
- 在浮点不可靠的世界里,robustness is everything。
📚 延伸阅读
"若要在几何世界里站稳脚跟,你必须征服浮点数。"