有两种测试平面凹多边形的“基本”方法:
-
转换为凸集并测试点和所有面之间的叉积方向
转换为凸多边形并不容易,但它可以通过三角测量或剪耳或任何方法来实现......之后只需检查叉积......所以如果你的凸多边形有顶点p0,p1,p2,...,p(n-1)并进行测试然后点p
d0 = cross( p-p0 , p0-p(n-1) );
for (i=1;i<n;i++)
{
di = cross( p-p(i), p(i)-p(i-1) );
if ( dot ( d0 , di ) <=0.0 ) return false;
}
return true;
所以只需检查所有多边形并返回子结果的 OR
-
使用命中测试
你从你的点向平行于你的平面的任何方向投射光线,并计算你的光线对多边形边缘的命中次数。如果它的奇数点在里面,它的偶数点在外面。 您问题中的链接使用此算法。但是在 3D 中,您需要更改方向,使其仍然在平面内……例如,使用多边形的单边 dir=p1-p0 作为您的方向。您还必须为光线直接击中顶点的情况编写一些规则,以便只计算一次而不是多次。此外,命中必须以 3D 形式计算,因此您需要轴/线相交。可以在这里找到:
只需寻找line closest(axis a0,line l1) 函数。它返回线,它是线和轴之间最近的连接。然后只需检查两个点是否相同(线的长度为零)。
现在为了简化这一点,您可以将 3D 数据移植到 2D
这样可以解决一些与平面四舍五入相关的精度问题...
您只需忽略一个坐标即可完成此操作。这很简单,但可能会带来一些舍入问题,而且结果具有不同的形状(在每个轴上缩放不同),因此指标不再相同,如果将其用于其他目的或任何类型的阈值,则可能会带来其他问题用过。
有更好的方法。我们需要任意 2 个基向量 u,v,它们垂直于每个基向量并且在您的平面内,并且在平面内有一个点 o。这很简单:
o = p0; // any point from the polygon
u = p1-p0; // any edge of polygon
u /= |u|; // normalize
v = p2-p1; // any other edge of polygon
v /= |v|; // normalize
for (;fabs(dot(u,v)>0.75;) // if too parallel
{
v=(p(1+rand(n-1))-p0); // chose random "edge"
v /= |v|; // normalize
}
v=cross(u,v); // make u,v perpendicular
v=cross(v,u); // and inside the plane
v /= |v|; // normalize just in case because of rounding the size might not be unit anymore
现在将点 p(x,y,z) 从 3D 转换为 2D (x,y) 只需这样做:
x = dot(p-o,u);
y = dot(p-o,v);
转换回 3D:
p = o + x*u + y*v;
通过这种转换方式,度量是相同的,所以多边形边的长度和多边形的大小不会改变......