Кватернион и ось вращения

На этот вопрос ответили. Ниже приведена большая часть кода, необходимого для его работы! Надеюсь, что это помогает другим.

Спасибо @Aki Suihkonen, @David Hammen и @MBo.

Обе функции угла дают правильный ответ.

У меня есть три пункта:

A: 12 4 5
B: 6 8 -10
C: 5 6 7

Я реализовал кватернионы. Я хочу повернуть точку C, чтобы угол (A, B, C) был на 40 градусов выше, чем раньше.

У меня вопрос: по какой оси я должен вращаться? Я предположил, что, поскольку A, B и C создают плоскость, я должен повернуть точку C в соответствии с перпендикулярной осью к векторам BA и BC. Я получил его с CrossProduct их единичных векторов, но когда я пытаюсь получить угол (A, B, C), это не дает мне правильный результат.

Вот как я получаю угол: (по-старому)

results:
Angle of ABC before rotation = 67.3895.
Angle of ABC after rotation = 107.389.

float Angle( float x1, float y1, float z1,
float x2, float y2, float z2 )
{
float x, y, z;
CrossProduct( x1, y1, z1, x2, y2, z2, &x, &y, &z );

float result = atan2 ( L2Norm( x, y, z ),
DotProduct( x1, y1, z1, x2, y2, z2 ) );

return result;
}

Где x1, y1, z1, x2, y2, z2 являются результатами от единичных векторов B-A и B-C.

Обновлена ​​функция угла:

results:
Angle of ABC before rotation = 67.3895.
Angle of ABC after rotation = 107.389.

Angle( Atom &atom1, Atom &atom2, Atom &atom3 )
{
float px1, py1, pz1;
float px2, py2, pz2;

UnitVector( atom1.X(), atom1.Y(), atom1.Z(),
atom2.X(), atom2.Y(), atom2.Z(),
&px1, &py1, &pz1 );UnitVector( atom3.X(), atom3.Y(), atom3.Z(),
atom2.X(), atom2.Y(), atom2.Z(),
&px2, &py2, &pz2 );

float dot_product = DotProduct( px1, py1, pz1, px2, py2, pz2 );
float length_BA = sqrt( px1*px1 + py1*py1 + pz1*pz1 );
float length_BC = sqrt( px2*px2 + py2*py2 + pz2*pz2 );

return acos( dot_product / ( length_BA * length_BC ) );
}

float DotProduct( float x1, float y1, float z1,
float x2, float y2, float z2 )
{
return x1*x2 + y1*y2 + z1*z2;
}

void CrossProduct( float x1, float y1, float z1,
float x2, float y2, float z2,
float *ox, float *oy, float *oz )
{
*ox = (y1*z2) -(z1*y2);
*oy = -((x1*z2) -(z1*x2));
*oz = (x1*y2) -(y1*x2);
}

Итак, мой вопрос: по какой оси я должен повернуть точку C, чтобы угол (A, B, C) был на 40 градусов больше, чем раньше?

  // The 3 points.
Atom A( "A", -4, 2 , 8 );
Atom B( "B", -1, 3 , 4 );
Atom C( "C", -2, -4 , 5 );

float x1, y1, z1;
float x2, y2, z2;
float x, y, z;

// Get the cross product. Create the perpendicular vector to the BA and BC vectors.
PointVector( A.X(), A.Y(), A.Z(), B.X(), B.Y(), B.Z(), &x1, &y1, &z1 );
PointVector( C.X(), C.Y(), C.Z(), B.X(), B.Y(), B.Z(), &x2, &y2, &z2 );

CrossProduct( x1, y1, z1, x2, y2, z2, &x, &y, &z );

// Normalize the coordinates.
float length = sqrt( x*x + y*y + z*z );
length = 1.0 / length;

x *= length;
y *= length;
z *= length;

// Create the 40 degrees angle. It is supposed to increment the current ABC angle by 40 degrees.
float angle = 40*M_PI/180;
float sinAngleOver2 = sin(angle/2);
float w = cos(angle/2);

// Create the axis quat.
Quatd q(w, x * sinAngleOver2, y * sinAngleOver2, z * sinAngleOver2);

// Create the point quaternal. The angle of it equals to the current ABC angle.
angle = Angle( A, B, C ) *180/M_PI;
angle *= M_PI/180;
sinAngleOver2 = sin(angle/2);
w = cos(angle/2);

// Normalize the coordinates. The coordinates are the C point coordinates.x = C.X() - B.X();
y = C.Y() - B.Y();
z = C.Z() - B.Z();

length = sqrt( x*x + y*y + z*z );
length = 1.0 / length;

x *= length;
y *= length;
z *= length;Quatd qpt(w, x * sinAngleOver2, y * sinAngleOver2, z * sinAngleOver2);

// Rotate.
qpt = q*qpt*q.unitInverse();

Atom new_C;
new_C.X( qpt.x + B.X() );
new_C.Y( qpt.y + B.Y() );
new_C.Z( qpt.z + B.Z() );

cout << "Angle: " << Angle( A, B, new_C )*180/M_PI << '\n';

4

Решение

Этот код неверен:

// Normalize the coordinates. The coordinates are the C point coordinates.
length = sqrt( C.X()*C.X() + C.Y()*C.Y() + C.Z()*C.Z() );
length = 1.0 / length;

x = C.X() / length;
y = C.Y() / length;
z = C.Z() / length;

Вы запутались, повторно используя свой length переменная для хранения 1 / length, Вам нужно умножить компоненты C от length чтобы нормализовать ваш вектор здесь.

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

Лично я бы реализовал какое-то умножение кватерниона на вектор или преобразовал кватернион в матрицу, чтобы выполнить преобразование.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]