问题描述
我正在尝试为分子建模问题叠加两个 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.看起来像简单的代数 - 为什么这不起作用?感谢您的帮助.
正如其他评论所暗示的,您很可能对投影和测角学感到困惑.还有一种更安全的方法,无需使用矢量数学(线性代数)进行测角.
创建变换矩阵
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
所以只需将它们提供给变换矩阵(请参阅答案底部的链接)
创建变换矩阵
m1
表示对齐平面到第二个三角形t1
与#1
相同计算最终变换矩阵
m
将t1
转换为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;it0 = 逆(m1)*m0矩阵_inv(m,m1);矩阵_mul(m,m,m0);//t2 = 转换后的 t1for (i=0;i
我用了我自己的矩阵和向量数学希望如果没有看到评论就足够了:
红色是
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 thearctan(-y/x)
. But, plugging this value for the angle back into the original equation above does not give zero except in the case wherex=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).
create transform matrix
m0
representing aligned plane to first trianglet0
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 arex,y,z
with origino
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)
create transform matrix
m1
representing aligned plane to second trianglet1
its the same as #1
compute final transform matrix
m
convertingt1
tot0
that is simple:
m = Inverse(m1)*m0
Now any point from
t1
can be aligned tot0
simply by multiplyingm
matrix by the point. Do not forget to use homogenuous coordinates sopoint(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 ist1
triangle and green is them*t1
transformed triangle. As you can see no need for goniometrics/euler angles at all. I rotate the stuff byarot
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 三角形的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!