3D вращение круга, чтобы край пересек две точки

1

Я пытаюсь сделать круг (фактически плоский цилиндр) вращаться так, чтобы край пересекал две точки в мировом положении. Эти две точки могут находиться где угодно на сфере. Сфера имеет тот же радиус и положение, что и цилиндр. происхождение обоих составляет [0,0,0].

Это немного сложно объяснить, поэтому я включил три фотографии, которые, я надеюсь, иллюстрируют то, что я пытаюсь выполнить.

Изображение 174551

Здесь вы видите, что я пытаюсь выполнить. Желтый круг представляет одну из точек вдоль сферы, а красный круг представляет другую точку. Синяя линия - фактически плоский цилиндр, проходящий через сферу, и вращается так, что он проходит через обе точки.

Изображение 174551

Вот еще одна подобная картина, но с точками в разных местах.

Изображение 174551

На этом снимке цилиндр можно увидеть полностью, поскольку сфера скрыта.

Теперь, я действительно ужасен в математике, поэтому мне действительно понравился бы ответ, составленный из псевдокода или языка программирования. И если мне так повезет, что я. Вращение кругов может быть представлено либо кватернионом, либо матрицей

Пока что я попытался, вращает цилиндр с вектором вверх в одну из точек и передний вектор по направлению к другой точке. Но я не могу заставить его работать. Я также пробовал другие решения, большинство из которых связаны с двумя поворотами (по одному для каждой точки), но в итоге у меня возникают проблемы при объединении поворотов.

Вот мой текущий нерабочий код:

Этот код заставляет круг проходить через первую точку, а затем поворачивает его с помощью "вектора вверх" в одну и ту же точку, это второе вращение изменяется в зависимости от положения первой точки и отслежено по всему месту.

//calculate direction vector between the two points
point1point2dir.set(point1Pos);
//subtract point two position
point1point2dir.sub(point2Pos);
//normalize
point1point2dir.nor();

//make two quaternions for rotation
Quaternion rot1=new Quaternion();
Quaternion rot2=new Quaternion();


//set first rotation two a rotation between X-axis and point1 position. Vector3.X = (1,0,0)
rot1.set(m.quatUtils.getRot(Vector3.X, point1Pos));

//crossmuliply direction vector between the two points with X-axis
point1point2dir.crs(Vector3.X);

//set the second rotation to a rotation between Z-Axis and the crossmultiplied direction vector
rot2.set(m.quatUtils.getRot(Vector3.Z, point1point2dir));

//multiply the two rotations
rot1.mul(rot2);

//apply the rotation to the cylinders matrix
cylinderMatrix.rotate(rot1);


//the function that gets the quaternion rotation between two vectors
Quaternion getRot(Vector3 pStart, Vector3 pDest) {
    start.set(pStart);
    dest.set(pDest);

    start.nor();
    dest.nor();

    cosTheta = Vector3.dot(start.x, start.y, start.z, dest.x, dest.y,
            dest.z);
    rotationAxis.set(0.0f, 0.0f, 0.0f);

    if (cosTheta < -1.0f + 0.001f) {

        rotationAxis.set(Z_AXIS);
        rotationAxis.crs(start);

        if (rotationAxis.len2() < 0.01f) {
            rotationAxis.set(X_AXIS);
            rotationAxis.crs(start);
        }

        rotationAxis.nor();
        resultQuat.set(rotationAxis, 180.0f);
        return resultQuat;
    }

    rotationAxis.set(start);
    rotationAxis.crs(dest);

    s = (float) Math.sqrt((1 + cosTheta) * 2);
    invs = 1.0f / s;
    resultQuat.set(rotationAxis.x * invs, rotationAxis.y * invs,
            rotationAxis.z * invs, s * 0.5f);
    return resultQuat;
}
Теги:
math
matrix
3d
quaternions

3 ответа

1

Я понял решение! Это было действительно просто. Я не знаю, как мне удалось свести математику так же сильно, как и раньше. Я на самом деле потратил много времени на это> :)

Извините, если я потратил впустую время anybodys!

Решение:

  1. найдите вектор направления из точки 1 (A) в точку 2 (B).
  2. crossmultiply direction vector с точкой2 для получения (C)
  3. Найдите кватернион, представляющий поворот от оси Z к вектору поперечного умножения (C), функция для этого включена в код, связанный с вопросом.
  4. примените поворот.

Вот рабочий код (yay):

        //the rotation
    Quaternion rot=new Quaternion();

    //the direction from point1 to point 2 (the point positions are in this case also the direction vectors from center)
    point1point2dir.set(point1Pos);
    point1point2dir.sub(point2Pos);
    point1point2dir.nor();  
    //crossmultiplied with point2
    point1point2dir.crs(point2Pos); 

    //set the rotation to the rotation between Z-axis and the crossmultiplied direction between point 1 and 2
    rot.set(m.quatUtils.getRot(Vector3.Z, point1point2dir));    

    //apply rotation
    ekvatorMatrix.rotate(rot);

И вот код для функции, возвращающий кватернион между двумя векторами:

    Quaternion getRot(Vector3 pStart, Vector3 pDest) {
    start.set(pStart);
    dest.set(pDest);

    start.nor();
    dest.nor();

    cosTheta = Vector3.dot(start.x, start.y, start.z, dest.x, dest.y,
            dest.z);
    rotationAxis.set(0.0f, 0.0f, 0.0f);

    if (cosTheta < -1.0f + 0.001f) {

        rotationAxis.set(Z_AXIS);
        rotationAxis.crs(start);

        if (rotationAxis.len2() < 0.01f) {
            rotationAxis.set(X_AXIS);
            rotationAxis.crs(start);
        }

        rotationAxis.nor();
        resultQuat.set(rotationAxis, 180.0f);
        return resultQuat;
    }

    rotationAxis.set(start);
    rotationAxis.crs(dest);

    s = (float) Math.sqrt((1 + cosTheta) * 2);
    invs = 1.0f / s;
    resultQuat.set(rotationAxis.x * invs, rotationAxis.y * invs,
            rotationAxis.z * invs, s * 0.5f);
    return resultQuat;
}
1

Я бы предложил это решение:

  1. Вычислите v1 и v2 как векторы от центра сферы к каждой точке, которую вы хотите, чтобы цилиндр проходил через корыто.

  2. Переверните произведение v1 и v2, чтобы получить вектор вверх по цилиндру, назовем его n.

  3. Расположите центр цилиндра в центре сферы.

  4. Поверните цилиндр, используя n как вектор вверх.

  • 0
    спасибо за Ваш ответ! :)
0

Предполагая, что начальный цилиндр ориентирован по оси с концами "круга" в положительном и отрицательном направлении X, и если предположить, что цилиндр и сфера первоначально имеют размер единицы (радиус = 1,0), я бы сделал следующее:

  1. Преобразуйте представление координат мира из красных и "желтых" точек (пусть просто для удовольствия назовите их A и B мы должны) до нормализованных векторов, указывающих из центра [0,0,0] (отныне называемого C)

  2. Вычислите угол между CA и CB (который действительно находится только между A и B). Позвольте называть этот угол W

  3. Вычислите вектор, перпендикулярный как A, так и B, выполнив кросс-произведение. Позволяет называть этот новый вектор D.

  4. Найдите матрицу вращения, которая вращается от [0,0,1] до B. Позволяет вызвать этот M1. Это можно сделать так же, как в пункте 3 (создать перпендикулярный вектор и повернуть вокруг него единичную матрицу с углом между нормализованными векторами).

  5. Найдите матрицу вращения, вращающую W вокруг D. Позвольте называть это M2

  6. Объединить M1 + M2 в M3

  7. Вы получаете M3

Это не было проверено, и поэтому я не знаю, работает ли это.

  • 0
    Этот ответ действительно близок к решению. Отличная работа!
  • 0
    Ну, спасибо, сэр!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню