Проблема наложения и выравнивания трехмерных треугольников - PullRequest
0 голосов
/ 03 сентября 2018

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

0 голосов
/ 04 сентября 2018

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

  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);
    }
//---------------------------------------------------------------------------

Я использовал свою собственную матрицу и векторную математику, надеюсь, комментариев будет достаточно, если не увидите:

Для получения информации о матрицах, вы также найдете источники и уравнения для математики, используемые там. Вот превью для моего теста:

preview

Где красный - t0 треугольник, синий - t1 треугольник, а зеленый - m*t1 преобразованный треугольник. Как вы можете видеть, нет необходимости в гониометрии / углах Эйлера. Я поворачиваю материал на arot, чтобы визуально проверить, действительно ли зеленый треугольник выровнен с синим, чтобы доказать, что я не сделал глупой ошибки.

Теперь неясно, как именно вы хотите выровнять, например, если вы хотите максимальное покрытие или что-то еще, попробуйте все 3 комбинации и запомните лучшую или выровняйте по ближайшим или наибольшим ребрам обоих треугольников и т. Д. *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...