0
$\begingroup$

What I'm trying to do...

Say I have two vectors. I want to align these vectors so that they one of my vectors is pointing directly at the other. For example, imagine there is this point and I want to position my camera so that my camera's center is directly aligned with said point.

From my understanding to do this, I would calculate the cross product between the two vectors and use that as an arbitrary axis of rotation.

From there I would need an angle $\theta,$ which can be determined by taking the dot product between the two vectors and dividing by the product of their magnitudes. Then I would solve for $\theta$ using $\cos^{-1}$

$$\theta=\cos^{-1}{A \cdot B\over |A||B|}$$

I'm stuck on how to determine the appropriate rotation matrix which to rotate about.

Also, I'm not sure if my process is correct I was looking online to figure this out.

$\endgroup$
0
$\begingroup$

I'm guessing you're intending to program this. So an implementation of @EmilioNovati's reference is illustrated below in C. You give it a rotation axis and a $\theta$, and then one function gives you the corresponding quaternion, and then another gives you the $3\mbox{x}3$ rotation matrix corresponding to that quaternion. And a third just conveniently multiplies a vector times a matrix to do the rotation for you. Here's the code, followed by a sample animation using it for rotation calculations...

/* ---
 * Point and line datatype structs
 * ---------------------------------- */
#define POINT struct point_struct       /* "typedef" for point_struct*/
#define LINE struct line_struct         /* "typedef" for line_struct*/
#define QUAT struct quaternion_struct   /* "typedef" for quaternion_struct */
POINT   { double x, y, z; } ;           /* 3d pts */
LINE    { POINT pt1, pt2; } ;           /* for vectors, pt1=tail, pt2=head */
QUAT    { double q0, q1, q2, q3; } ;    /* quat = q0 + q1*i + q2*j + q3*k */

/***************************************************************************
 ** +===================================================================+ **
 ** | Low-level quaternion functions, etc                               | **
 ** +===================================================================+ **
 ***************************************************************************/

/* ==========================================================================
 * 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;                     /* i-component */
   q.q2 = qsin*y/r;                     /* j-component */
   q.q3 = qsin*z/r; }                   /* k-component */
 return ( q );
 } /* --- end-of-function qrotate() --- */


/* ==========================================================================
 * Function:    qmatrix ( QUAT q )
 * Purpose:     returns 3x3 rotation matrix corresponding to quaternion q
 *              ( can just be called as qmatrix(qrotate(axis,theta))
 *                for rotation matrix around axis through theta )
 * --------------------------------------------------------------------------
 * 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 128 3x3 matrices
 *              returned to the caller one at a time. So you may issue
 *              128 qmatrix() calls and continue using all returned matrices.
 *              The 129th call re-uses the memory used by the 1st call, etc.
 * ======================================================================= */
/* --- entry point --- */
double  *qmatrix ( QUAT q ) {
 /* --- allocations and declarations --- */
 static double Qbuff[128][9];           /* up to 128 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 > 127 ) 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() --- */


/* ==========================================================================
 * Function:    qmultiply ( double *Q, POINT u, int istranspose )
 * Purpose:     returns Q*u (u a column vector) if istranspose=0,
 *                   or u*Q (u a row vector)    if istranspose=1.
 * --------------------------------------------------------------------------
 * Arguments:   Q (I)           double *Q to rotation matrix returned
 *                              by qmatrix (or by some similar construction)
 *              u (I)           POINT u to column vector (or to row vector
 *                              if istranspose=1) to be multiplied by Q
 *                              (or to multiply Q if istranspose=1)
 *              istranspose (I) int istranspose=0 to return Q*u (u a col vec),
 *                              or  istranspose=1 to return u*q (u a row vec)
 * --------------------------------------------------------------------------
 * Returns:     ( POINT )       Q*u (istranspose=0), or u*Q (istranspose=1)
 * --------------------------------------------------------------------------
 * Notes:     o Q assumed to be a 3x3 matrix stored row-wise
 * ======================================================================= */
/* --- entry point --- */
POINT   qmultiply ( double *Q, POINT u, int istranspose ) {
 /* --- allocations and declarations --- */
 POINT  Qu = { 0.,0.,0. };              /* Q*u (or u*Q if istranspose=1) */
 double x=u.x, y=u.y, z=u.z;            /* x(i),y(j),z(k)-components of u */
 /* --- Q*u --- */
 if ( !istranspose ) {
   Qu.x = Q[0]*x + Q[1]*y + Q[2]*z;     /*  first row of Q * column vector u */
   Qu.y = Q[3]*x + Q[4]*y + Q[5]*z;     /* second row of Q * column vector u */
   Qu.z = Q[6]*x + Q[7]*y + Q[8]*z;     /*  third row of Q * column vector u */
   } /* --- end-of-if(!istranspose) --- */
 /* --- u*Q --- */
 if ( istranspose ) {
   Qu.x = x*Q[0] + y*Q[3] + z*Q[6];     /* row vector u *  first column of Q */
   Qu.y = x*Q[1] + y*Q[4] + z*Q[7];     /* row vector u * second column of Q */
   Qu.z = x*Q[2] + y*Q[5] + z*Q[8];     /* row vector u *  third column of Q */
   } /* --- end-of-if(istranspose) --- */
 /* --- return product to caller --- */
 return ( Qu );
 } /* --- end-of-function qmultiply() --- */

And here's a sample animation that uses the above functions to perform the frame-by-frame rotations... enter image description here

$\endgroup$
  • $\begingroup$ Thanks for the explanation! My mathematical background isn't enough to understand this completely, but it is a good jump off point for me to learn from. If this works with what I'm doing I will mark it as correct! $\endgroup$ – Markus T. Jul 26 '18 at 21:53
  • $\begingroup$ @MarkusT. Yeah, I noticed your other "community" is stackoverflow, and figured you're likely heading in this direction (but for this type of stuff, python might not be your best choice:) $\endgroup$ – John Forkosh Jul 26 '18 at 22:40
  • $\begingroup$ I thought about that, but If I only need to call the quaternion once wouldn't it not be that bad? The plan is that I'm given a vector and I need to move a robotic arm to that position based on the quaternion. In that regard would I really need to iterate through the program that much? $\endgroup$ – Markus T. Jul 26 '18 at 23:16
  • $\begingroup$ @MarkusT. Sure, if you're only doing it a few times, python (or an abacus, for that matter:) "wouldn't be that bad". $\endgroup$ – John Forkosh Jul 27 '18 at 8:46
0
$\begingroup$

Yes, the rotation axis is oriented by the vector orthogonal to the two vectors, but we have to use a normalized vector $$\vec u=\frac{\vec a \times \vec b}{|\vec a||\vec b|}$$, and the angle $\theta$ of rotation is obtained from the inner product of the two vectors as you have done.

The matrix that represents the rotation around the axis $\vec u$ of angle $\theta$ is given here.

$\endgroup$
0
$\begingroup$

If you look at https://wikimedia.org/api/rest_v1/media/math/render/svg/f259f80a746ee20d481f9b7f600031084358a27c formula from wikipedia(I don't have enough rep to include the image)

we obtain the general formula for a rotation matrix about an axis defined by the vector $(u_x,u_y,u_z)$. As you said, we obtain the angle between two vectors $v$ and $w$ with $\frac{v\cdot w}{|v||w|}$ and plug that in for theta. Then we take $v\times w$ to be the vector $u$.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.