2011-12-05 96 views
4

我正试图在线平面相交算法中实现。根据Wikipedia,我需要在飞机上有三个非共线点来做到这一点。如何在飞机上获得三个非共线点? - C++

因此,我试着在C++中实现this algorithm。有些东西肯定是错的,因为我可以选择任何x和y坐标并且它们适合在飞机中是没有意义的。如果飞机是垂直的并沿着x轴呢?那么y = 1的点就不在飞机上了。

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

现在的问题是,我被normal.z分,而当normal.z为0

我与这架飞机的测试显然是行不通的:平面* P =新的Plane(Color(),Vec3d(0.0,0.0,0.0),Vec3d(0.0,1.0,0.0)); //第二个参数:位置,第三个参数:正常

当前的代码给出了这样的不正确的答案:

{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; 
} 

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

在此先感谢。

+0

实际上,您可以用方程式'ax + by + cz == d'来描述任何平面。任何具有'b == 0.0'的平面都将平行于y轴(如您所描述的那样),因为在这种情况下,'y'的值不会影响(in)的平等。 – comingstorm

回答

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不是沿着正常的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; 

一条线由点和方向定义。典型地,两个点(Q1Q2)定义直线和平面的交点由点上相交,使得DOT(r-P1,N)=0的平面中的线r=Q1+t*E限定的线

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

。这解决了沿线标量距离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]); 
+0

我认为这是一个非常实际且平易近人的答案,我明白代码清单2中的叉积有效地旋转了法线向量,是的,我还想知道,如果没有交集,会发生什么?你的线平面相交算法将列表4中的代码赋给''t''产生垃圾还是除零?谢谢。 –

+0

@ user309483 - 交叉乘积从两个向量中找出共同的法线,它不一定是如果平面法线'N'垂直于线方向'E',那么它们的点积是零,'t'除以零。 – ja72

+0

非常感谢,我现在用C++实现了它,它工作正常。希望代码能够向我发送消息! –

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=Origin+sK+tL一些s,t平面上的任何点p

+0

第一种方法失败的一种情况是法向量的三个分量都相同(例如N =(1,1,1))。 – andand

+0

更健壮的方法:if | Nx |> | Ny |那么P =( - Nz,0,Nx)否则P =(0,-Nz,Ny) – MBo

+0

我不知道我明白这一点:“如果'M!= N''是一个任意向量”。用“!=”表示“不等于”,对吧?一个布尔表达式的结果怎么可能是一个向量?谢谢你的耐心。我知道“K = MxN是共线的”,因为它们相互平等,因此你的意思是它们都是共线的。“但是,当它是”不等于“时,我应该如何解释它? –

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) 

你需要的工作输出S对于d以及另一个系数为0的情况,以及d和另外两个为0。应该总共有16个案例,但是有几件事情会让人想起来,这应该使这个更容易管理。