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

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

Благодаря @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 своих единичных векторов, но когда я пытаюсь получить Angle (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
nl ja de
Учитывая имя, я сильно подозреваю, что L2Norm вычисляет норму [1 = L2] входного вектора. Другими словами, он вычисляет евклидову длину вектора. [1] mathworld.wolfram.com/L2-Norm.html
добавлено автор David Hammen, источник
Вы не указали код для того, как вы вращаете C, так что это просто предположение: вы вращаете C о происхождении . Это не то, что вы хотите сделать. Вам нужно повернуть C вокруг B.
добавлено автор David Hammen, источник
Что делает функция L2Norm? Вы можете рассчитать угол как результат = arccos (DotProduct (x1, y1, z1, x2, y2, z2)/(BA.Length * CA.Length))
добавлено автор MBo, источник
О оси вращения - да, ваше решение с CrossProduct прекрасное, это вектор направления этой оси. Что касается угла - вы пытаетесь использовать какое-то решение в 2D-случае, здесь неправильно
добавлено автор MBo, источник
Я имею в виду B-A и C-A, потому что вы использовали «векторы B-A и C-A», и я думал об A как о точке вращения. Забудьте о знаменателе, если вы используете единичные векторы.
добавлено автор MBo, источник
Да, ось вращения будет плоской нормалью, которая является нормированным поперечным произведением двух векторов, определяющих плоскость. Однако, как было предложено MBo (и я в вашем другом потоке), ваша функция Angle может потребоваться пересмотреть. Он дает 89.926, а arccos дает 80.841 (в градусах).
добавлено автор Aki Suihkonen, источник
добавлено автор glomad, источник
Вы делаете заметку о алгоритме углов или имеете в виду, что если я удалю L2Norm, я получу желаемый результат?
добавлено автор user985611, источник
Не уверен. Формула atan2 для этого объяснялась именно так. Я считаю, что видел это на одном из форумов matlab. Что касается оси, у вас есть решение?
добавлено автор user985611, источник
Я пересмотрю функцию угла и посмотрю, работает ли она. Спасибо за помощь до сих пор @ Аки. Если бы я мог, я бы дал вам 1000 очков. :) Я еще кое-что: только точка C должна двигаться. Я не могу переместить остальных. Это похоже на головоломку, а точка C должна вращаться таким образом, чтобы создать определенный угол.
добавлено автор user985611, источник
Для тех, кто задается вопросом, что такое L2Norm: return sqrtf (pow (x, 2) + pow (y, 2) + pow (z, 2));
добавлено автор user985611, источник
result = arccos (DotProduct (x1, y1, z1, x2, y2, z2)/(BA.Length CA.Length)). Вы имеете в виду BA.Length BC.Length? (Если B - средняя точка)?
добавлено автор user985611, источник
Я просто протестировал эту функцию. Угол (A, B, C) со средней точкой B составляет 67.3895. Когда я поворачиваю точку C, я получаю 75.4952. Я считаю, что ошибка находится где-то в коде, который я только что вставил в свой основной пост.
добавлено автор user985611, источник
Я обновлялся, чтобы отразить: где x1, y1, z1, x2, y2, z2 - результаты от единичных векторов B-A и B-C.
добавлено автор user985611, источник
Обновлен основной пост с большим количеством кода.
добавлено автор user985611, источник

1 ответы

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

// 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
добавлено
Победа! Огромное спасибо. Он работает сейчас. Я обновляю главный пост с правильным кодом, чтобы каждый мог воспользоваться. Если бы это было красноватым, я бы отдал всем!
добавлено автор user985611, источник
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

Infernal Math
Infernal Math
389 участник(ов)

http://www.zepta.ru/index.php?title=Заглавная_страница Приглашение в чат: https://t.me/matheden

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

comput.math
comput.math
289 участник(ов)

Прикладная математика и численные методы. Без оффтопа, рекламы, флуда. Вышмат: @higher_math Физика: @physpub Новичкам: @starter_math @JuliaLanguage @rlang_ru Книги брать здесь: libgen.io И по хештегу #book

higher.math
higher.math
234 участник(ов)

Higher mathematics / высшая математика Подборка книжек: https://ru.stackoverflow.com/a/683632/1084 Вычмат: @comput_math Физика: @physpub LaTeX: @pro_latex

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest

Starter Math
Starter Math
79 участник(ов)

Для тех, кто боится спросить в @higher_math Вычмат: @comput_math Физика: @physpub