Проблема наложения и выравнивания трехмерных треугольников

Я пытаюсь наложить два трехмерных треугольника для задачи молекулярного моделирования. Это казалось достаточно простым. Я перевел первую точку каждого треугольника в начало координат, 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 ответ

Как и предполагали другие комментарии, вы, скорее всего, запутались в прогнозах и гониометрии. Существует также более безопасный способ без гониометрии с использованием векторной математики (линейной алгебры).

  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
    

    так что просто введите их в матрицу преобразования (см. ссылку внизу ответа)

  2. создать матрицу преобразования m1 представляет выровненную плоскость ко второму треугольнику t1

    это так же, как #1

  3. вычислить окончательную матрицу преобразования 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 комбинации и запомните лучшую или выровняйте по ближайшим или наибольшим ребрам обоих треугольников и т.д....

Другие вопросы по тегам