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.
问题:
回答1:
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 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:
- Understanding 4x4 homogenous transform matrices
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 ...