叠加和对齐 3D 三角形的问题 [英] Problem superimposing and aligning 3D triangles

查看:19
本文介绍了叠加和对齐 3D 三角形的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为分子建模问题叠加两个 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. 创建变换矩阵 m0 表示对齐平面到第一个三角形 t0

    对齐我的意思是三角形的边之一应该位于平面基向量之一中.这很简单,您只需将一个基向量设置为有问题的边,将原点设置为其点之一,然后利用叉积得到剩余的向量.

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

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

    所以只需将它们提供给变换矩阵(请参阅答案底部的链接)

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

    #1

  3. 相同
  4. 计算最终变换矩阵 mt1 转换为 t0

    这很简单:

    m = Inverse(m1)*m0

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

这里是C++/OpenGL小例子:

//--------------------------------------------------------------------------double t0[3][3]=//第一个三角形{-0.5,-0.5,-1.2,+0.5,-0.5,-0.8,0.0,+0.5,-1.0,};double t1[3][3]=//第二个三角形{+0.5,-0.6,-2.1,+1.5,-0.5,-2.3,+1.2,+0.3,-2.2,};双 arot=0.0;//动画角度//--------------------------------------------------------------------------void gl_draw()//主要渲染代码{诠释我;双 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);//渲染原始三角形glBegin(GL_TRIANGLES);glColor3f(1.0,0.0,0.0);对于 (i=0;i<3;i++) glVertex3dv(t0[i]);glColor3f(0.0,0.0,1.0);对于 (i=0;i<3;i++) glVertex3dv(t1[i]);glEnd();//x,y,z = t0 平面基向量vector_sub(x,t0[1],t0[0]);//x 是第一条边vector_one(x,x);//标准化vector_sub(y,t0[2],t0[0]);//y 是最后一条边vector_mul(z,x,y);//z = cross(x,y) ... 与 x,y 垂直的向量vector_one(z,z);vector_mul(y,z,x);//y = cross(z,x) ... 与 z,x 垂直的向量vector_one(y,y);//m0 = 表示 t0 平面的变换矩阵m0[3]=0.0;对于 (i=0;i<3;i++) m0[ 0+i]=x[i];m0[7]=0.0;对于 (i=0;i<3;i++) m0[ 4+i]=y[i];m0[11]=0.0;对于 (i=0;i<3;i++) m0[ 8+i]=z[i];m0[15]=1.0;对于 (i=0;i<3;i++) m0[12+i]=t0[0][i];//x,y,z = t1 平面基向量vector_sub(x,t1[1],t1[0]);//x 是第一条边vector_one(x,x);//标准化vector_sub(y,t1[2],t1[0]);//y 是最后一条边vector_mul(z,x,y);//z = cross(x,y) ... 与 x,y 垂直的向量vector_one(z,z);vector_mul(y,z,x);//y = cross(z,x) ... 与 z,x 垂直的向量vector_one(y,y);//m1 = 表示 t1 平面的变换矩阵m1[3]=0.0;对于 (i=0;i<3;i++) m1[ 0+i]=x[i];m1[7]=0.0;对于 (i=0;i<3;i++) m1[ 4+i]=y[i];m1[11]=0.0;对于 (i=0;i<3;i++) m1[ 8+i]=z[i];m1[15]=1.0;对于 (i=0;i<3;i++) m1[12+i]=t1[0][i];//m = 变换 t1 ->t0 = 逆(m1)*m0矩阵_inv(m,m1);矩阵_mul(m,m,m0);//t2 = 转换后的 t1for (i=0;i<3;i++) matrix_mul_vector(t2[i],m,t1[i]);//渲染变换的三角形glLineWidth(2.0);glBegin(GL_LINE_LOOP);glColor3f(0.0,1.0,0.0);对于 (i=0;i<3;i++) glVertex3dv(t2[i]);glLineWidth(1.0);glEnd();glFlush();交换缓冲区(hdc);}//--------------------------------------------------------------------------

我用了我自己的矩阵和向量数学希望如果没有看到评论就足够了:

  • 红色是 t0 三角形,蓝色是 t1 三角形,绿色是 m*t1 变换后的三角形.如您所见,根本不需要测角学/欧拉角.我通过 arot 旋转这些东西,只是为了直观地检查绿色三角形是否真的与蓝色对齐,以证明我没有犯愚蠢的错误.

    现在还不清楚您想要如何对齐,例如,如果您想要最大的覆盖率或尝试所有 3 种组合并记住最好的或对齐两个三角形的最近或最大边缘等...

    I am trying to superimpose two 3D triangles for a molecular modeling problem. It seemed simple enough. I translated the first point of each triangle to the origin, 0,0,0. I then calculated the angle I would have to rotate around the z axis to put the second point on the x axis. Using the formula for x,y,z for Rz(theta) this would be the angle where y=0, y=xsin(theta)+ycos(theta)=0, and rearranging, tan(theta)=-y/x The angle would be the arctan(-y/x). But, plugging this value for the angle back into the original equation above does not give zero except in the case where x=y, and the tangent is one. Seems like simple algebra - why doesn't this work? Thanks for any help.

    解决方案

    As the other comments suggested you most likely got confused withing projections and goniometrics. There is also safer way without goniometrics using vector math (linear algebra).

    1. create transform matrix m0 representing aligned plane to first triangle t0

      by aligned I mean one of the edges of triangle should lie in the one of the plane basis vectors. That is simple you just set one basis vector as the edge in question, origin as one of its point and exploit the cross product to get the remainding vectors.

      so if our triangle has points p0,p1,p2 and our basis vectors are x,y,z with origin o then:

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

      so just feed those to the transform matrix (see the link in bottom of answer)

    2. create transform matrix m1 representing aligned plane to second triangle t1

      its the same as #1

    3. compute final transform matrix m converting t1 to t0

      that is simple:

      m = Inverse(m1)*m0
      

    Now any point from t1 can be aligned to t0 simply by multiplying m matrix by the point. Do not forget to use homogenuous coordinates so point(x,y,z,1)

    Here small C++/OpenGL example:

    //---------------------------------------------------------------------------
    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);
        }
    //---------------------------------------------------------------------------
    

    I used my own matrix and vector math hope the comments are enough if not see:

    For info about the matrices and you will find the sources and equations for the math used there too. Here preview for my test case:

    Where red is t0 triangle blue is t1 triangle and green is the m*t1 transformed triangle. As you can see no need for goniometrics/euler angles at all. I rotate the stuff by arot just to visually check if the green triangle really align to the blue to prove me I did not make a silly mistake.

    Now its unclear how exactly you want to align, so for example if you want maximal coverage or something either try all 3 combinations and remember the best or align to closest or largest edges of both triangles etc ...

    这篇关于叠加和对齐 3D 三角形的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆