叠加和对齐3D三角形时出现问题

时间:2018-09-03 17:16:22

标签: geometry

我正在尝试为一个分子建模问题叠加两个3D三角形。看起来很简单。我将每个三角形的第一个点转换为原点0,0,0。然后,我计算了必须绕z轴旋转的角度才能将第二个点放到x轴上。使用Rz(theta)的x,y,z公式,这将是y=0的角度, y=xsin(theta)+ycos(theta)=0,然后重新排列tan(theta)=-y/x 角度将为arctan(-y/x)。但是,除非在x=y且切线为1的情况下,将此角度的值重新插入到上面的原始公式中不会得到零。看起来像简单的代数-为什么不起作用? 感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

正如其他评论所建议的那样,您很可能与投影和测角法混淆了。还有一种不使用矢量数学(线性代数)进行测角的安全方法。

  1. 创建表示将平面对齐到第一个三角形m0的变换矩阵t0

    通过对齐,我的意思是三角形的边缘之一应位于平面基向量之一中。很简单,您只需将一个基本向量设置为所讨论的边缘,将原点设置为其要点之一,并利用叉积获得剩余向量。

    因此,如果我们的三角形有点p0,p1,p2,并且我们的基向量是x,y,z,且原点为o,那么:

    x = p1-p0;      x /= |x|;
    y = p2-p0; 
    z = cross(x,y); z /= |z|;
    y = cross(z,x); y /= |y|;
    o = p0
    

    所以只需将它们输入到变换矩阵(请参见答案底部的链接)

  2. 创建表示将平面对齐到第二个三角形m1的变换矩阵t1

    #1

  3. 相同
  4. 计算最终转换矩阵m,将t1转换为t0

    这很简单:

    m = Inverse(m1)*m0
    

现在,只需将t1矩阵乘以该点即可将t0中的任何点与m对齐。不要忘记使用同质坐标,因此point(x,y,z,1)

以下为 C ++ / OpenGL 示例:

//---------------------------------------------------------------------------
double t0[3][3]=    // 1st triangle
    {
    -0.5,-0.5,-1.2,
    +0.5,-0.5,-0.8,
     0.0,+0.5,-1.0,
    };
double t1[3][3]=    // 2nd triangle
    {
    +0.5,-0.6,-2.1,
    +1.5,-0.5,-2.3,
    +1.2,+0.3,-2.2,
    };
double arot=0.0; // animation angle
//---------------------------------------------------------------------------
void gl_draw()      // main rendering code
    {
    int i;
    double m0[16],m1[16],m[16],x[3],y[3],z[3],t2[3][3];

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslated(0.0,0.0,-10.0);
    glRotatef(arot,0.0,1.0,0.0); 

    // render original triangles
    glBegin(GL_TRIANGLES);
    glColor3f(1.0,0.0,0.0); for (i=0;i<3;i++) glVertex3dv(t0[i]);
    glColor3f(0.0,0.0,1.0); for (i=0;i<3;i++) glVertex3dv(t1[i]);
    glEnd();

    // x,y,z = t0 plane basis vectors
    vector_sub(x,t0[1],t0[0]);  // x is fisrt edge
    vector_one(x,x);            // normalized
    vector_sub(y,t0[2],t0[0]);  // y is last edge
    vector_mul(z,x,y);          // z = cross(x,y) ... perpendicular vector to x,y
    vector_one(z,z);
    vector_mul(y,z,x);          // y = cross(z,x) ... perpendicular vector to z,x
    vector_one(y,y);
    // m0 = transform matrix representing t0 plane
    m0[ 3]=0.0; for (i=0;i<3;i++) m0[ 0+i]=x[i];
    m0[ 7]=0.0; for (i=0;i<3;i++) m0[ 4+i]=y[i];
    m0[11]=0.0; for (i=0;i<3;i++) m0[ 8+i]=z[i];
    m0[15]=1.0; for (i=0;i<3;i++) m0[12+i]=t0[0][i];

    // x,y,z = t1 plane basis vectors
    vector_sub(x,t1[1],t1[0]);  // x is fisrt edge
    vector_one(x,x);            // normalized
    vector_sub(y,t1[2],t1[0]);  // y is last edge
    vector_mul(z,x,y);          // z = cross(x,y) ... perpendicular vector to x,y
    vector_one(z,z);
    vector_mul(y,z,x);          // y = cross(z,x) ... perpendicular vector to z,x
    vector_one(y,y);
    // m1 = transform matrix representing t1 plane
    m1[ 3]=0.0; for (i=0;i<3;i++) m1[ 0+i]=x[i];
    m1[ 7]=0.0; for (i=0;i<3;i++) m1[ 4+i]=y[i];
    m1[11]=0.0; for (i=0;i<3;i++) m1[ 8+i]=z[i];
    m1[15]=1.0; for (i=0;i<3;i++) m1[12+i]=t1[0][i];

    // m = transform t1 -> t0 = Inverse(m1)*m0
    matrix_inv(m,m1);
    matrix_mul(m,m,m0);

    // t2 = transformed t1
    for (i=0;i<3;i++) matrix_mul_vector(t2[i],m,t1[i]);

    // render transformed triangle
    glLineWidth(2.0);
    glBegin(GL_LINE_LOOP);
    glColor3f(0.0,1.0,0.0); for (i=0;i<3;i++) glVertex3dv(t2[i]);
    glLineWidth(1.0);
    glEnd();

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------

我使用了自己的矩阵和矢量数学,希望看到的注释足够多:

有关矩阵的信息,您还将找到那里使用的数学的来源和方程式。在这里预览我的测试用例:

preview

红色是t0三角形,蓝色是t1三角形,绿色是m*t1变换后的三角形。如您所见,根本不需要测角/欧拉角。我将arot旋转,只是为了目视检查绿色三角形是否真的对准蓝色,以证明我没有犯傻。

现在不清楚您要对齐的精确度,例如,如果您想要最大的覆盖范围,或者尝试全部3种组合并记住最佳组合或对齐两个三角形的最近或最大边缘,等等...