给定由三角网格表示的边界定义的三维多面体,如何实现一个算法来确定给定的3D点是否属于多面体的内部?
答案 0 :(得分:1)
有几种方法可以实现此功能。
最简单的方法是从点开始创建无限光线(或非常长的线段)并指向任意方向,然后计算光线和三角形之间的交叉点数。如果交点的数量是奇数,则该点在多面体内。
Inside(Polyhedron P, point q)
Segment S = [q, q+(0,0,1e30)]
count = 0
For each triangle T of P
If Intersect(S,T)
count = count + 1
End if
End for
return odd(count)
End
现在计算一个段和一个三角形之间是否存在交叉的函数:
Intersect([q1,q2],(t1,t2,t3))
s1 = orient3d(q1,t1,t2,t3)
s2 = orient3d(q2,t1,t2,t3)
// Test whether the two extermities of the segment
// are on the same side of the supporting plane of
// the triangle
If(s1 == s2)
return false
End if
// Now we know that the segment 'straddles' the supporing
// plane. We need to test whether the three tetrahedra formed
// by the segment and the three edges of the triangle have
// the same orientation
s3 = orient3d(q1,q2,t1,t2)
s4 = orient3d(q1,q2,t2,t3)
s5 = orient3d(q1,q2,t3,t1)
return (s3 == s4 AND s4 == s5)
End
最后,orient3d函数:
Orient3d(a,b,c,d)
// Computes the sign of the signed volume
// of the tetrahedron (a,b,c,d)
return Sign( dot(cross(b-a,c-a),d-a) )
End
现在有两个大问题:
如果浮点精度不够,会发生什么 计算Orient3d?
当所选片段完全通过a时会发生什么 顶点或三角形的边缘?
对于1.,必须使用任意精确的算术[1]。在[2]中,参考文献[1](Jonathan Shewchuk)的作者公开了orient3d()的实现。 Geogram中还有一个实现,我自己的编程库[3]。
现在为2.,它更棘手,最好的方法是实现符号扰动[4]。简而言之,我们的想法是“消除歧义”配置,其中orient3d()通过考虑点沿着时间参数化的轨迹移动而返回零,并且当时间趋于零时采用位置的限制(另一种说法:如果位置没有给出答案,请在时间t = 0时查看“速度矢量”。原始参考文献[4]给出了“多边形点”测试(问题的2D版本)的orient2d()的符号扰动。
注意:如果你很懒并且你不想实现符号扰动,你可以在每次orient3d()测试返回零时选择一个随机方向(那么你不能保证它不会永远搜索,但是练习它不太可能发生)。无论如何,我建议仅将其用于原型设计,并最终实现符号扰动。
[1] https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf
[2] https://www.cs.cmu.edu/~quake/robust.html
[3] http://alice.loria.fr/software/geogram/doc/html/index.html