Поверните трехмерную систему координат так, чтобы ось Z была параллельна заданному вектору.

Предположим, у меня есть декартовый Икс у г система координат с точкой п "=" ( п Икс , п у , п г ) . Кроме того, вектор н "=" ( н Икс , н у , н г ) дано.

  1. Как повернуть систему координат, чтобы получить новую ты в ж система такая, что ж -ось параллельна вектору н ?

  2. Как получить координаты г. п в ты в ж -система?

Ответы (3)

На основе ответа @Muphrid и с использованием формулы, приведенной по адресу:

http://answers.google.com/answers/threadview/id/361441.html

Я резюмирую шаги для дальнейшего использования:

Позволять н ^ "=" н / н , θ "=" потому что 1 ( к ^ н ^ ) , б "=" к ^ × н ^ , и б ^ "=" ( б ^ Икс , б ^ у , б ^ г ) "=" б / б . Затем определите:

  • д 0 "=" потому что ( θ / 2 ) ,
  • д 1 "=" грех ( θ / 2 ) б ^ Икс ,
  • д 2 "=" грех ( θ / 2 ) б ^ у ,
  • д 3 "=" грех ( θ / 2 ) б ^ г ,

и

Вопрос "=" [ д 0 2 + д 1 2 д 2 2 д 3 2 2 ( д 1 д 2 д 0 д 3 ) 2 ( д 1 д 3 + д 0 д 2 ) 2 ( д 2 д 1 + д 0 д 3 ) д 0 2 д 1 2 + д 2 2 д 3 2 2 ( д 2 д 3 д 0 д 1 2 ( д 3 д 1 д 0 д 2 ) 2 ( д 3 д 2 + д 0 д 1 ) д 0 2 д 1 2 д 2 2 + д 3 2 ] .

Тогда мы имеем:

  • ты ^ "=" Вопрос я ^ ,
  • в ^ "=" Вопрос Дж ^ ,
  • ж ^ "=" Вопрос к ^ "=" н ^ .

Новая координата п становится

( п ты , п в , п ж ) "=" ( п ты ^ , п в ^ , п ж ^ )

Да, я предполагаю, что в Matlab может не быть хорошей встроенной функции преобразования кватерниона в матрицу, или, возможно, они предполагают, что вы просто будете использовать quats для вращения, не переходя к матричному представлению.
Извините, что комментирую так долго после вашего поста, но я наткнулся на этот вопрос и ответ, почти опубликовав аналогичный вопрос только сейчас. Твой к ^ н аргумент потому что 1 ... которые должны быть н ^ , верно? Единичный вектор в н -направление (иначе потому что 1 могут выйти за пределы аргументов)? Спасибо.
@JohnForkosh Спасибо за комментарий! Я обновил ответ.
Спасибо за разъяснения, Хокон. Я добавил «ответ» ниже, который просто расширяет этот комментарий, потому что изображение нельзя поместить в комментарий...

Есть два эквивалентных способа сделать это.

Позволять Икс ^ , у ^ , г ^ быть вашими базисными векторами. первый подход заключается в построении карты вращения, отображающей г ^ г ^ "=" н ^ . Затем, изображения Икс ^ , у ^ , г ^ равны новым координатным базисным векторам ты ^ , в ^ , ж ^ . Вы можете извлечь компоненты из п используя скалярные произведения (т.е. п ты "=" п ты ^ и так далее) в обычном порядке. Геометрически речь идет о вращении осей, чтобы найти новые базисные векторы.

Другой вариант — построить обратную карту, которая отображает н ^ г ^ . Затем Икс у г -компоненты любого вектора изображения ты в ж -компоненты соответствующего входного вектора. Геометрически вы вращаете все входные данные, сохраняя фиксированную систему координат, поэтому вы можете извлекать новые компоненты, используя старую основу координат. Вы никогда не найдете новые базисные векторы таким образом, но они вам абсолютно не нужны. Таким образом, образ п при таком вращении будет п ты Икс ^ + п в у ^ + п ж г ^ .


Таким образом, большой вопрос заключается в том, как вычислить карту вращения. Делать это с матрицами может быть довольно обременительно. Я предлагаю решение с использованием кватернионов. Найдите ось, перпендикулярную г ^ и н , вероятно, используя перекрестное произведение. Назовите эту ось б ^ . Найдите угол θ между г ^ и н , вероятно, используя г ^ н ^ "=" потому что θ . Запишите все векторы, используя чисто мнимые кватернионы, и вы сможете создать карту вращения.

р ( а ) "=" е б ^ θ / 2 а е б ^ θ / 2

Если вы нашли б ^ используя г ^ × н ^ , то это соответствует первому описанному мною случаю, вращению г ^ н ^ . Если вы выбрали б ^ вместо этого это вращается н ^ г ^ , что соответствует второму случаю.

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

Спасибо за интересный ответ. Но я собираюсь использовать это в компьютерной программе, и я не знаком с кватернионами.
Это так? Кватернионы широко используются в компьютерном программировании, поэтому их использование часто поддерживается (поэтому вам обычно не нужно реализовывать их с нуля). Какой язык вы используете?
Я использую Матлаб.
Хорошо, Matlab, похоже, имеет достойную поддержку кватернионов и может вычислить матрицу вращения, соответствующую данному кватерниону. См. mathworks.com/discovery/quaternion.html .
Спасибо! Я попробую это. Что на самом деле а в приведенной выше формуле?
Любой входной вектор.
Основываясь на вашем ответе, я резюмирую шаги, которые я использовал для расчета решения в Matlab, в моем ответе ниже.

Спасибо, что разъяснили ваш предыдущий ответ в ответ на мой комментарий, @HåkonHægland. Я очень внимательно изучил его, потому что хочу/намереваюсь закодировать его в своей программе C "stringart" (технически, "symmography"), которая делает такие вещи. .

введите описание изображения здесь

Таким образом, код проективной геометрии уже вроде как работает, но является случайным/уродливым/и т. д., и я намеревался разработать небольшую библиотеку для этих манипуляций и попытаться написать ее как можно элегантнее. Итак, я хочу сначала полностью и правильно понять подход (кватернионы, углы Эйлера, что у вас есть) и соответствующую математику.

Изменить. Я собрал первую часть этой маленькой библиотеки на основе ваших алгоритмов выше (и на странице ответов. Google, на которую вы ссылаетесь), которая находится под gpl'ed и которую вы можете получить с http: //www.forkosh .com/quatrot.c

Имеет встроенный тестовый драйвер

cc -DQRTESTDRIVE quatrot.c -lm -o quatrot

и, похоже, работает именно так, как вы рекламировали. Блок комментариев в тестовом драйвере main() содержит простые инструкции по использованию. Я еще не на 100% доволен функциональной декомпозицией, т.е. она должна быть одновременно простой в использовании для программиста и интуитивно понятной для математика. Но главное, что это работает (насколько я проверял, кажется). Всего 460 строк, поэтому я не буду приводить все это здесь (во всяком случае, проще взять по ссылке выше). Две функции, в основном основанные на answer.google, это...

/* ==========================================================================
 * Function:    qrotate ( LINE axis, double theta )
 * Purpose:     returns quaternion corresponding to rotation
 *              through theta (**in radians**) around axis
 * --------------------------------------------------------------------------
 * Arguments:   axis (I)        LINE axis around which rotation by theta
 *                              is to occur
 *              theta (I)       double theta rotation **in radians**
 * --------------------------------------------------------------------------
 * Returns:     ( QUAT )        quaternion corresponding to rotation
 *                              through theta around axis
 * --------------------------------------------------------------------------
 * Notes:     o Rotation direction determined by right-hand screw rule
 *              (when subsequent qmultiply() is called with istranspose=0)
 * ======================================================================= */
/* --- entry point --- */
QUAT    qrotate ( LINE axis, double theta )
{
/* --- allocations and declarations --- */
QUAT    q = { cos(0.5*theta), 0.,0.,0. } ; /* constructed quaternion */
double  x = axis.pt2.x - axis.pt1.x,    /* length of x-component of axis */
        y = axis.pt2.y - axis.pt1.y,    /* length of y-component of axis */
        z = axis.pt2.z - axis.pt1.z;    /* length of z-component of axis */
double  r = sqrt((x*x)+(y*y)+(z*z));    /* length of axis */
double  qsin = sin(0.5*theta);          /* for q1,q2,q3 components */
/* --- construct quaternion and return it to caller */
if ( r >= 0.0000001 ) {                 /* error check */
  q.q1 = qsin*x/r;                      /* x-component */
  q.q2 = qsin*y/r;                      /* y-component */
  q.q3 = qsin*z/r; }                    /* z-component */
return ( q );
} /* --- end-of-function qrotate() --- */

/* ==========================================================================
 * Function:    qmatrix ( QUAT q )
 * Purpose:     returns 3x3 rotation matrix corresponding to quaternion q
 * --------------------------------------------------------------------------
 * Arguments:   q (I)           QUAT q for which a rotation matrix
 *                              is to be constructed
 * --------------------------------------------------------------------------
 * Returns:     ( double * )    3x3 rotation matrix, stored row-wise
 * --------------------------------------------------------------------------
 * Notes:     o The matrix constructed from input q = q0+q1*i+q2*j+q3*k is:
 *                    (q0²+q1²-q2²-q3²)    2(q1q2-q0q3)     2(q1q3+q0q2)
 *                Q  =   2(q2q1+q0q3)   (q0²-q1²+q2²-q3²)   2(q2q3-q0q1)
 *                       2(q3q1-q0q2)      2(q3q2+q0q1)  (q0²-q1²-q2²+q3²)
 *            o The returned matrix is stored row-wise, i.e., explicitly
 *                --------- first row ----------
 *                qmatrix[0] = (q0²+q1²-q2²-q3²)
 *                       [1] =    2(q1q2-q0q3)
 *                       [2] =    2(q1q3+q0q2)
 *                --------- second row ---------
 *                       [3] =    2(q2q1+q0q3)
 *                       [4] = (q0²-q1²+q2²-q3²)
 *                       [5] =    2(q2q3-q0q1)
 *                --------- third row ----------
 *                       [6] =    2(q3q1-q0q2)
 *                       [7] =    2(q3q2+q0q1)
 *                       [8] = (q0²-q1²-q2²+q3²)
 *            o qmatrix maintains a static buffer of 64 3x3 matrices
 *              returned to the caller one at a time. So you may issue
 *              64 qmatrix() calls and continue using all returned matrices.
 *              But the 65th call re-uses the memory used by the 1st call, etc.
 * ======================================================================= */
/* --- entry point --- */
double  *qmatrix ( QUAT q )
{
/* --- allocations and declarations --- */
static  double Qbuff[64][9];            /* up to 64 calls before wrap-around */
static  int    ibuff = (-1);            /* Qbuff[ibuff][] index 0<=ibuff<=63 */
double  *Q = NULL;                      /* returned ptr Q=Qbuff[ibuff] */
double  q0=q.q0, q1=q.q1, q2=q.q2, q3=q.q3; /* input quaternion components */
double  q02=q0*q0, q12=q1*q1, q22=q2*q2, q32=q3*q3; /* components squared */
/* --- first maintain Qbuff[ibuff][] buffer --- */
if ( ++ibuff > 63 ) ibuff=0;            /* wrap Qbuff[ibuff][] index */
Q = Qbuff[ibuff];                       /* ptr to current 3x3 buffer */
/* --- just do the algebra described in the above comments --- */
Q[0] = (q02+q12-q22-q32);
Q[1] =  2.*(q1*q2-q0*q3);
Q[2] =  2.*(q1*q3+q0*q2);
Q[3] =  2.*(q2*q1+q0*q3);
Q[4] = (q02-q12+q22-q32);
Q[5] =  2.*(q2*q3-q0*q1);
Q[6] =  2.*(q3*q1-q0*q2);
Q[7] =  2.*(q3*q2+q0*q1);
Q[8] = (q02-q12-q22+q32);
/* --- return constructed quaternion to caller */
return ( Q );
} /* --- end-of-function qmatrix() --- */

Это тестовый драйвер main(), который содержит код, основанный на вашем дополнительном обсуждении. Икс , у , г ты , в , ж , а затем проецирование заданной точки п чтобы получить компоненты по новым осям (фрагмент)...

  int   ipt=0, npts=4;                  /* testpoints[] index, #test points */
  POINT testpoints[] = {                /* test points for quatrot funcs */
        {000.,000.,000.}, {100.,000.,000.}, {000.,100.,000.}, {000.,000.,100.}
        } ;
  /* --- test data for simple rotations around given test axis --- */
  QUAT  q = qrotate(axis,pi*theta/180.); /* rotation quaternion */
  double *Q = qmatrix(q);               /* quat rotation matrix */
  /* --- test data to rotate z-axis to given axis and project points --- */
  double thetatoz = acos(dotprod(khat,unitvec(axis))); /* rotate axis to z */
  LINE  bhat = unitvec(crossprod(khat,unitvec(axis))); /* as per stackexch */
  QUAT  qtoz = qrotate(bhat,thetatoz);  /* quat to rotate z to axis */
  double *Qtoz = qmatrix(qtoz);         /* quat matrix to rotate z to axis */
  LINE  uhat = { {0.,0.,0.}, qmultiply(Qtoz,ihat.pt2,0) }, /*new x-axis*/
        vhat = { {0.,0.,0.}, qmultiply(Qtoz,jhat.pt2,0) }, /*new y-axis*/
        what = { {0.,0.,0.}, qmultiply(Qtoz,khat.pt2,0) }; /*z=testaxis?*/
  /* --- apply rotations/projections to testpoints[] --- */
  fprintf(msgfp,"      theta: %.3f\n",theta);
  prtline ("       axis:",&axis);
  for ( ipt=0; ipt<npts; ipt++ ) {      /* rotate each test point */
    /* --- select test point --- */
    POINT pt = testpoints[ipt];         /* current test point */
    /* --- rotate test point around axis in existing x,y,z coords --- */
    POINT ptrot = qmultiply(Q,pt,0);    /* rotate pt around axis by theta */
    POINT pttran= qmultiply(Q,pt,1);    /* transpose rotation */
    /* --- project test point to rotated axes, where given axis=z-axis --- */
    POINT pttoz = {dotprod(pt,uhat),dotprod(pt,vhat),dotprod(pt,what)} ;
    /* --- display test results --- */
    fprintf(msgfp,"testpoint#%d...\n",ipt+1);
    prtpoint("     testpoint: ",&pt);   /* current test point... */
    prtpoint("       rotated: ",&ptrot);  /* ...rotated around given axis */
    prtpoint(" transpose rot: ",&pttran); /* ...transpose rotation */
    prtpoint("   axis=z-axis: ",&pttoz);  /* ...coords when axis=z-axis */
    } /* --- end-of-for(ipt) --- */

Фрагмент выше может быть немного труден для чтения вне контекста (полный контекст см. в функции main()), но там есть такие вещи, как...

  /* --- test data to rotate z-axis to given axis and project points --- */
  double thetatoz = acos(dotprod(khat,unitvec(axis))); /* rotate axis to z */
  LINE  bhat = unitvec(crossprod(khat,unitvec(axis))); /* as per stackexch */
  QUAT  qtoz = qrotate(bhat,thetatoz);  /* quat to rotate z to axis */
  double *Qtoz = qmatrix(qtoz);         /* quat matrix to rotate z to axis */
  LINE  uhat = { {0.,0.,0.}, qmultiply(Qtoz,ihat.pt2,0) }, /*new x-axis*/
        vhat = { {0.,0.,0.}, qmultiply(Qtoz,jhat.pt2,0) }, /*new y-axis*/
        what = { {0.,0.,0.}, qmultiply(Qtoz,khat.pt2,0) }; /*z=testaxis?*/

что в значительной степени дословно, так сказать, то, что вы написали выше. По крайней мере, я на это надеюсь. :)