Проблема наложения и выравнивания трехмерных треугольников
Я пытаюсь наложить два трехмерных треугольника для задачи молекулярного моделирования. Это казалось достаточно простым. Я перевел первую точку каждого треугольника в начало координат, 0,0,0. Затем я рассчитал угол, который мне нужно было бы повернуть вокруг оси z, чтобы поместить вторую точку на оси x. Используя формулу для x,y,z для Rz(тета), это будет угол, где 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 = 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 комбинации и запомните лучшую или выровняйте по ближайшим или наибольшим ребрам обоих треугольников и т.д....