一种简单的方法是将实体表示为半空间的交集。
3d 平面有隐式方程:
ax + by + cz + d = 0
其中(a, b, c) 是平面法线,d 是平面任意点的-(a*x + b*y + c*z) 值(计算的值不会取决于您选择的点)。
对于平面一侧的空间点,a*x+ b*y + c*z + d 的结果将为负数,而另一侧的结果将为正数。
柏拉图立体(任何凸立体)可以表示为所有面的非正侧上的空间点,即
a[i]*x + b[i]*y + c[i]*z + d[i] <= 0
因此,一个相当快的测试可能是:
struct Plane {
double a, b, c, d;
};
struct Point {
double x, y, z;
};
int side(const Point pt, const Plane& pl) {
double v = pt.x*pl.a + pt.y*pl.b + pt.z*pl.c + pl.d;
if (v < -EPS) return -1;
if (v > EPS) return 1;
return 0;
}
struct ConvexSolid {
std::vector<Plane> planes;
bool contains(const Point& pt) const {
return std::all_of(planes.begin(), planes.end(),
[&](const Plane& pl){
return side(pt, pl) <= 0;
});
}
};
此外,如果您知道自己的大部分观点都在实体范围内,那么添加快速接受测试可能是个好主意。考虑中心和与面的距离......如果您的点位于以中心为中心的球体内并且具有该半径,那么肯定也在实体内。
因此,如果您预计许多点都在该范围内,那么首先检查它可能是一项不错的投资,因为它只需要检查
r2 = (x-xc)*(x-xc) + (y-yc)*(y-yc) + (z-zc)*(z-zc)
这应该比检查一架飞机的成本略高。
但是请注意,如果大多数点不在该范围内,那么进行此检查确实是一种悲观。
另一个加速方法是同时考虑边界球具有相同的中心...在这种情况下,您只能使用相同的r2 计算来进行“波段”检查,您将仅当r2 > r2min(即,如果该点不在内球体内)和r2 < r2max(即,如果该点不在外球体内)时才需要运行完整检查。