是否有任何已知方法可快速有效地确定3D点是否位于已知大小的柏拉图体积内?
这似乎很容易与立方体(六面体)或圆形(椭圆体)做。对于四面体,八面体,十二面体或二十面体,我似乎无法弄清楚。我猜测可能可以将形状分解为几个子实体,然后检查每个子实体,但我想尽可能避免使用任何一种迭代求解器。
一种简单的方法是将实体表示为半空间的交集。
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
(即,该点不在外球体外部)时进行完整检查。
如果您正在寻找一种优化的算法,则可以尝试检查该点是否在实体的边界球之外,并仅在不存在边界的情况下才对曲面进行检查。
point in polygon在确定2D点是否位于任何类型的多边形(2D空间)内的情况下是众所周知的问题。参见例如
[polyhedra(3D)中的点问题是-对于任何类型的多面体来说-都有些棘手。但是,在您的情况下,您严格考虑使用convex多面体,因为所有柏拉图式固体都是后一种。
在这种情况下,我可以为您指出解决此问题的两种方法。1 :(任何凸面
polytope
的通用方法))您可以将问题视为查找某个点是否在一组已知点的convex hull内,在这种情况下,您的点就是顶点柏拉图式的实体,它们准确地描述了自己的凸包(由于凸性,没有“内部”顶点)。例如,已经讨论了如何实现该问题的一般解决方案。在这里:decisionVariable = myPoint
(强制包含)的情况下,如果该点不可行,则LP不可行位于您的多面体之外,或者是可行的(否则,无需解决最优性,仅出于可行性)。2:如上所述,对多边形中的2D点进行了深入研究,甚至可以为其找到C ++代码in the SO link I provided above。由于您正在考虑3D中的凸多面体,因此我们知道切穿这种多面体的2D平面的交点将描述凸多边形。因此,对于要调查的每个点,您将创建一个包含该点并且与多面体(您的柏拉图式实体)相交的平面:然后,剩下的问题是求解
“”多边形问题中的2D点“]这架飞机。