如何得到平面上的三个非共线点?——c++



我正在尝试实现线面相交算法。根据维基百科的说法,我需要平面上的三个非共线点来做到这一点。

因此,我尝试在c++中实现这个算法。肯定是有问题的,因为我不能任意选择x和y坐标让它们在平面上匹配。如果平面垂直于x轴呢?此时平面上没有y=1的点

我意识到这个问题已经在StackOverflow上发布了很多,我看到很多解决方案,其中平面由3个点定义。但我只有一个正常和一个位置。在我整理好我的非共线寻点器之前,我不能测试我的线面相交算法。

现在的问题是,我要除以normal。Z,这在正常情况下显然是行不通的。Z为0

我正在测试这个平面:plane * p = new plane (Color(), Vec3d(0.0,0.0,0.0), Vec3d(0.0,1.0,0.0));//第二个参数:position,第三个参数:normal

当前代码给出了这个错误的答案:

{0 , 0 , 0} // alright, this is the original
{12.8377 , 17.2728 , -inf} // obviously this is not a non-colinear point on the given plane

下面是我的代码:

std::vector<Vec3d>* Plane::getThreeNonColinearPoints() {
    std::vector<Vec3d>* v = new std::vector<Vec3d>();
    v->push_back(Vec3d(position.x, position.y, position.z)); // original position can serve as one of the three non-colinear points.
    srandom(time(NULL));
    double rx, ry, rz, start;
    rx = Plane::fRand(10.0, 20.0);
    ry = Plane::fRand(10.0, 20.0);
    // Formula from here: http://en.wikipedia.org/wiki/Plane_(geometry)#Definition_with_a_point_and_a_normal_vector
    // nx(x-x0) + ny(y-y0) + nz(z-z0) = 0
    // |-----------------| <- this is "start"
    //I'll try to insert position as x0,y0,z0 and normal as nx,ny,nz, and solve the equation
    start = normal.x * (rx - position.x) + normal.y * (ry - position.y);
    // nz(z-z0) = -start
    start = -start;
    // (z-z0) = start/nz
    start /= normal.z; // division by zero
    // z = start+z0
    start += position.z;
    rz = start;
    v->push_back(Vec3d(rx, ry, rz));
    // TODO one more point
    return v;
}
我意识到我可能试图解决这个问题完全错了。如果有,请链接具体执行。当我看到这么多线面相交的实现时,我确信它一定存在。

平面可以用几种方式定义。通常使用平面上的一个点和一个法向量。为了得到三个点(P1, P2, P3)的法向量,取三角形边的叉乘

P1 = {x1, y1, z1};
P2 = {x2, y2, z2};
P3 = {x3, y3, z3};
N = UNIT( CROSS( P2-P1, P3-P1 ) );
Plane P = { P1, N }

相反,从一个点P1和正常的N到三个点,你从任何方向G 沿着正常的N开始,这样DOT(G,N)!=0。则平面上的两个正交方向为

//try G={0,0,1} or {0,1,0} or {1,0,0}
G = {0,0,1};
if( MAG(CROSS(G,N))<TINY ) { G = {0,1,0}; }
if( MAG(CROSS(G,N))<TINY ) { G = {1,0,0}; }
U = UNIT( CROSS(N, G) );  
V = CROSS(U,N);
P2 = P1 + U;
P3 = P1 + V;

一条线由一个点和一个方向定义。通常两个点(Q1, Q2)定义

Q1 = {x1, y1, z1};
Q2 = {x2, y2, z2};
E = UNIT( Q2-Q1 );
Line L = { Q1, E }

直线与平面的交点由直线r=Q1+t*E上与平面相交的点DOT(r-P1,N)=0定义。对于沿直线的标量距离t求解为

t = DOT(P1-Q1,N)/DOT(E,N);

和位置

r = Q1+(t*E);

注意:DOT()返回两个向量的点积,CROSS()是叉积,UNIT()是单位向量(大小为1)。

DOT(P,Q) = P[0]*Q[0]+P[1]*Q[1]+P[2]*Q[2];
CROSS(P,Q) = { P[1]*Q[2]-P[2]*Q[1], P[2]*Q[0]-P[0]*Q[2], P[0]*Q[1]-P[1]*Q[0] };
UNIT(P) = {P[0]/sqrt(DOT(P,P)), P[1]/sqrt(DOT(P,P)), P[2]/sqrt(DOT(P,P))};
t*P =  { t*P[0], t*P[1], t*P[2] };
MAG(P) = sqrt(P[0]*P[0]+P[1]*P[1]+P[2]*P[2]);

一种容易实现的方法是查看平面与坐标轴的交点。对于由方程aX + bY + cZ - d = 0给出的平面,保持两个变量为0,并解出第三个变量。因此,解决方案将是(假设a, b, cd都是非零的):

(d/a, 0, 0)
(0, d/b, 0)
(0, 0, d/c)

你需要考虑一个或多个系数为0的情况,这样你就不会得到退化解或共线性解。例如,如果其中一个系数为0(例如a=0),则使用

(1, d/b, 0)
(0, d/b, 0)
(0, 0, d/c)

如果正好有两个系数是0(比如a=0b=0),你可以使用:

(1, 0, d/c)
(0, 1, d/c)
(0, 0, d/c)

如果d=0,平面与三个轴相交于原点,所以你可以使用:

(1, 0, -a/c)
(0, -c/b, 1)
(-b/a, 1, 0)

您将需要计算d和恰好另一个系数为0的类似情况,以及d和另外两个系数为0的类似情况。总共应该有16个案例,但是我想到了一些事情,这些事情应该会使这个案例更容易管理。

其中N=(Nx,Ny,Nz)为法线,您可以将N, (Ny,Nz,Nx), (Nz,Nx,Ny)点投影到平面上:它们保证是不同的。

或者,如果PQ在平面上,P+t(Q-P)xN也在任何t!=0的平面上,其中x是外积。

或者,如果M!=N是一个任意向量,则K=MxNL=KxN与平面共线,对于某些s,t,平面上的任何点p都可以写成p=Origin+sK+tL

相关内容

  • 没有找到相关文章

最新更新