如何在平面上获得三个非共线点? - C ++

时间:2011-12-05 14:56:54

标签: c++ math computational-geometry linear-algebra

我正在尝试在线平面交叉算法上实现。根据{{​​3}},我需要在飞机上有三个非共线点才能做到这一点。

然而,我尝试在C ++中实现Wikipedia。有些东西肯定是错的,因为没有任何意义我可以选择任何x和y坐标,它们将适合飞机。如果平面是垂直的并且沿着x轴怎么办? y = 1的任何一点都不会在平面上。

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

现在的问题是,我正在除以normal.z,当normal.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;
}

我意识到我可能试图解决这个完全错误的问题。如果是这样,请链接具体实现。当我看到很多线平面交叉实现时,我确信它必须存在。

提前致谢。

3 个答案:

答案 0 :(得分:5)

可以通过多种方式定义飞机。通常使用平面上的点和法向量。要从三个点(P1P2P3)获取法线向量,请取三角形边的叉积

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 而不是的任何方向开始{{ 1}}这样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()单位向量(幅度= 1)。

UNIT()

答案 1 :(得分:2)

您可能会发现一种易于实现的方法是查看平面与坐标轴相交的位置。对于由等式aX + bY + cZ - d = 0给出的平面,将两个变量保持为0并求解第三个变量。所以解决方案是(假设abcd都是非零的):

(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个案例,但那里我想到的一些事情应该会让人更容易管理。

答案 2 :(得分:1)

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与平面共线,则平面上的任何点p都可以写为{{1}对于某些p=Origin+sK+tL