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

Jan*_*sen 4 c++ math linear-algebra computational-geometry

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

因此,我尝试在C++中实现此算法.有些东西肯定是错的,因为没有任何意义我可以选择任何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
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

提前致谢.

ja7*_*a72 5

可以用几种方式定义平面.通常使用平面上的点和法向量.从三个点(获得法线矢量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 }
Run Code Online (Sandbox Code Playgroud)

相反,从一个点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;
Run Code Online (Sandbox Code Playgroud)

线由点和方向定义.通常两个点(Q1,Q2)定义该线

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

线和平面的交集被线路上的点限定r=Q1+t*E相交的平面上,使得DOT(r-P1,N)=0.这是t沿着线的标量距离求解的

t = DOT(P1-Q1,N)/DOT(E,N);
Run Code Online (Sandbox Code Playgroud)

和位置

r = Q1+(t*E);
Run Code Online (Sandbox Code Playgroud)

注意: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]);
Run Code Online (Sandbox Code Playgroud)