我正在尝试为一个分子建模问题叠加两个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的情况下,将此角度的值重新插入到上面的原始公式中不会得到零。看起来像简单的代数-为什么不起作用?
感谢您的帮助。
答案 0 :(得分: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
所以只需将它们输入到变换矩阵(请参见答案底部的链接)
创建表示将平面对齐到第二个三角形m1
的变换矩阵t1
与#1
计算最终转换矩阵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);
}
//---------------------------------------------------------------------------
我使用了自己的矩阵和矢量数学,希望看到的注释足够多:
有关矩阵的信息,您还将找到那里使用的数学的来源和方程式。在这里预览我的测试用例:
红色是t0
三角形,蓝色是t1
三角形,绿色是m*t1
变换后的三角形。如您所见,根本不需要测角/欧拉角。我将arot
旋转,只是为了目视检查绿色三角形是否真的对准蓝色,以证明我没有犯傻。
现在不清楚您要对齐的精确度,例如,如果您想要最大的覆盖范围,或者尝试全部3种组合并记住最佳组合或对齐两个三角形的最近或最大边缘,等等...