C# 共面检查器缺少某个案例
我构造了一个小函数来检查一组点是否共面:C# 共面检查器缺少某个案例,c#,geometry,C#,Geometry,我构造了一个小函数来检查一组点是否共面: public static bool IsCoplanar(Point[] points) { // Ensure there are greater than three points (otherwise always coplanar) if (points.Length < 4) { return true; } Point pointA = points[0]; Point
public static bool IsCoplanar(Point[] points)
{
// Ensure there are greater than three points (otherwise always coplanar)
if (points.Length < 4)
{
return true;
}
Point pointA = points[0];
Point pointB = points[1];
Point pointC = points[2];
// Calculate the scalar triple product using vectors formed from
// the first three points and each successive point to check that
// the point is on the same plane as the first three.
Vector vectorBA = pointB - pointA;
Vector vectorCA = pointC - pointA;
for (int i = 3; i < points.Length; i++)
{
Point pointD = points[i];
Vector vectorDA = pointD - pointA;
if (!(System.Math.Abs(vectorBA.Dot(vectorCA.Cross(vectorDA))) < Epsilon))
{
return false;
}
}
return true;
}
这些都很好。但如果你加上:
(50, -50, 50)
(50, -50, -50)
返回列表并再次运行,它仍然返回true
我已经研究这个问题很多年了,但是还没有发现问题,有人知道吗
谢谢。我看不出代码中有什么明显的地方,但您可以尝试稍微不同的方法 给定平面的公式:
Ax + By + Cz + D = 0
取定义平面的前三个点,生成系数a
、B
、C
和D
对于其余的点,请检查:
Point v;
float d = A * v.x + B * v.y + C * v.d;
d
现在是从该点到平面的距离,沿平面法线
如果d
小于d
(平面沿其法线到原点的距离),则该点位于该平面的后面(即法线指向的平面的另一侧)。如果d
大于d
,则该点位于平面前方
如果abs(d-d)
,则可以安全地假设该点位于平面内
示例()
给定空间中的点p,Q,R,求出通过这三个点的平面方程
如果p=(1,1,1),Q=(1,2,0),R=(-1,2,1)
我们寻求方程ax+by+cz=d的系数,其中p、Q和R满足方程,因此:
a + b + c = d
a + 2b + 0c = d
-a + 2b + c = d
从第二个方程中减去第一个方程,然后将第一个方程加到第三个方程中,我们去掉a得到
b - c = 0
4b + c = 2d
将这些方程相加,得到5b=2d或b=(2/5)d,然后求解c=b=(2/5)d,然后a=d-b-c=(1/5)d
所以方程(保留一个非零常数供选择)是d(1/5)x+d(2/5)y+d(2/5)z=d
,所以一个常数的选择
x + 2y + 2z = 5
或者,A
=1、B
=2、C
=2和D
=5
一旦你有了这些,检查其余的点就是简单地将点的x,y,z代入平面方程,并将输出与平面到原点的D距离进行比较
注意,系数也可以使用矩阵来求解一个由三个未知量的三个方程组成的系统。如果您已经有一个矩阵类可用,那么使用它来查找系数应该非常简单。下面是C#中的代码。注意,像Cross和Equal这样的操作应该是类运算符,我没有这样做。此外,我还包括了对重合点等情况的边缘案例测试。例如,如果输入是非唯一点,如(50,50,50)后跟(50,50,50),则当前代码失败
public static bool IsCoplanar(MyPoint[] points)
{
if (points.Length <= 3)
return true;
//input points may be the coincidental/same (edge case),
//so we first need to loop to find three unique points.
//the first unique point is by default at position 0,
//so we will start looking for second at position 1:
int unique_point2_index = 0;
int unique_point3_index = 0;
bool found_point2 = false;
bool found_point3 = false;
for (int i = 1; i < points.Length; ++i )
{
if (!found_point2)
{
if (!Equals(points[0], points[i]))
{
found_point2 = true;
unique_point2_index = i;
}
}
else if (!found_point3)
{
if (!Equals(points[0], points[i]) && !Equals(points[unique_point2_index], points[i]))
{
found_point3 = true;
unique_point3_index = i;
}
}
else
break;
}
//if we did not find three unique points, then all of the points are coplanar!
if (!found_point3)
return true;
//we found three unique points lets loop through the rest and check if those
//are also coplanar. We do that as following:
//First compute the plane normal:
MyPoint P1 = points[0];
MyPoint P2 = points[unique_point2_index];
MyPoint P3 = points[unique_point3_index];
MyPoint vecP1P2 = Minus(P2, P1); //Should be class operator, P2 - P1
MyPoint vecP1P3 = Minus(P3, P1);
MyPoint normal = Cross(vecP1P2, vecP1P3);
//Secondly, for the remainder of points, we compute
//a vector from P1 to each point,
//and take the dot product with the normal.
//This should be zero (+- epsilon) for coplanar points
for (int i = unique_point3_index + 1; i < points.Length; ++i)
{
MyPoint testVec = Minus(points[i], P1);
double dot = Dot(testVec, normal);
//include error boundary for double precision
if (Math.Abs(dot) > 0.000001)
return false;
}
return true;
}
public static bool IsCoplanar(MyPoint[]点)
{
如果(点长度0.000001)
返回false;
}
返回true;
}
Hi,我可能在切线上,但如果我正确地记住了我的叉积。。看看你的代码:CA-cross-DA将生成一个向量,该向量与这两个向量垂直,最有可能是非单位长度。向量BA(用于点积)也很可能不是单位。叉积向量可能在任一方向上,因此点积可以是负的,也可以是正的。你能做的就是规范化所有起作用的向量,然后检查点积的绝对值是否接近1(+-delta)。那应该能解决你的问题。嗯,好的。我对向量进行了归一化处理。当你说点积的绝对值时,你是指在我之前的解中计算的值吗?因为它仍然趋向于0而不是1(尽管我认为你们在一些向量的方向上并没有被考虑),点,向量和ε是什么?
public static bool IsCoplanar(MyPoint[] points)
{
if (points.Length <= 3)
return true;
//input points may be the coincidental/same (edge case),
//so we first need to loop to find three unique points.
//the first unique point is by default at position 0,
//so we will start looking for second at position 1:
int unique_point2_index = 0;
int unique_point3_index = 0;
bool found_point2 = false;
bool found_point3 = false;
for (int i = 1; i < points.Length; ++i )
{
if (!found_point2)
{
if (!Equals(points[0], points[i]))
{
found_point2 = true;
unique_point2_index = i;
}
}
else if (!found_point3)
{
if (!Equals(points[0], points[i]) && !Equals(points[unique_point2_index], points[i]))
{
found_point3 = true;
unique_point3_index = i;
}
}
else
break;
}
//if we did not find three unique points, then all of the points are coplanar!
if (!found_point3)
return true;
//we found three unique points lets loop through the rest and check if those
//are also coplanar. We do that as following:
//First compute the plane normal:
MyPoint P1 = points[0];
MyPoint P2 = points[unique_point2_index];
MyPoint P3 = points[unique_point3_index];
MyPoint vecP1P2 = Minus(P2, P1); //Should be class operator, P2 - P1
MyPoint vecP1P3 = Minus(P3, P1);
MyPoint normal = Cross(vecP1P2, vecP1P3);
//Secondly, for the remainder of points, we compute
//a vector from P1 to each point,
//and take the dot product with the normal.
//This should be zero (+- epsilon) for coplanar points
for (int i = unique_point3_index + 1; i < points.Length; ++i)
{
MyPoint testVec = Minus(points[i], P1);
double dot = Dot(testVec, normal);
//include error boundary for double precision
if (Math.Abs(dot) > 0.000001)
return false;
}
return true;
}