/src/q2m.c
C | 592 lines | 37 code | 201 blank | 354 comment | 4 complexity | e9b57ad636a28fa99f7f0413f3d857bb MD5 | raw file
- /* q2m.f -- translated by f2c (version 19980913).
- You must link the resulting object file with the libraries:
- -lf2c -lm (in that order)
- */
- #include "f2c.h"
- /* $Procedure Q2M ( Quaternion to matrix ) */
- /* Subroutine */ int q2m_(doublereal *q, doublereal *r__)
- {
- doublereal l2, q01, q02, q03, q12, q13, q23, sharpn, q1s, q2s, q3s;
- /* $ Abstract */
- /* Find the rotation matrix corresponding to a specified unit */
- /* quaternion. */
- /* $ Disclaimer */
- /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */
- /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */
- /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */
- /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */
- /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */
- /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */
- /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */
- /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */
- /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */
- /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */
- /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */
- /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */
- /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
- /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */
- /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */
- /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */
- /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */
- /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */
- /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */
- /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */
- /* $ Required_Reading */
- /* ROTATION */
- /* $ Keywords */
- /* MATH */
- /* MATRIX */
- /* ROTATION */
- /* $ Declarations */
- /* $ Brief_I/O */
- /* Variable I/O Description */
- /* -------- --- -------------------------------------------------- */
- /* Q I A unit quaternion. */
- /* R O A rotation matrix corresponding to Q. */
- /* $ Detailed_Input */
- /* Q is a unit-length SPICE-style quaternion. Q has the */
- /* property that */
- /* || Q || = 1 */
- /* See the discussion of quaternion styles in */
- /* Particulars below. */
- /* $ Detailed_Output */
- /* R is a 3 by 3 rotation matrix representing the same */
- /* rotation as does Q. See the discussion titled */
- /* "Associating SPICE Quaternions with Rotation */
- /* Matrices" in Particulars below. */
- /* $ Parameters */
- /* None. */
- /* $ Exceptions */
- /* Error free. */
- /* 1) If Q is not a unit quaternion, the output matrix M is */
- /* the rotation matrix that is the result of converting */
- /* normalized Q to a rotation matrix. */
- /* 2) If Q is the zero quaternion, the output matrix M is */
- /* the identity matrix. */
- /* $ Files */
- /* None. */
- /* $ Particulars */
- /* If a 4-dimensional vector Q satisfies the equality */
- /* || Q || = 1 */
- /* or equivalently */
- /* 2 2 2 2 */
- /* Q(0) + Q(1) + Q(2) + Q(3) = 1, */
- /* then we can always find a unit vector A and a scalar r such that */
- /* Q = ( cos(r/2), sin(r/2)A(1), sin(r/2)A(2), sin(r/2)A(3) ). */
- /* We can interpret A and r as the axis and rotation angle of a */
- /* rotation in 3-space. If we restrict r to the range [0, pi], */
- /* then r and A are uniquely determined, except if r = pi. In this */
- /* special case, A and -A are both valid rotation axes. */
- /* Every rotation is represented by a unique orthogonal matrix; this */
- /* routine returns that unique rotation matrix corresponding to Q. */
- /* The SPICELIB routine M2Q is a one-sided inverse of this routine: */
- /* given any rotation matrix R, the calls */
- /* CALL M2Q ( R, Q ) */
- /* CALL Q2M ( Q, R ) */
- /* leave R unchanged, except for round-off error. However, the */
- /* calls */
- /* CALL Q2M ( Q, R ) */
- /* CALL M2Q ( R, Q ) */
- /* might preserve Q or convert Q to -Q. */
- /* Quaternion Styles */
- /* ----------------- */
- /* There are different "styles" of quaternions used in */
- /* science and engineering applications. Quaternion styles */
- /* are characterized by */
- /* - The order of quaternion elements */
- /* - The quaternion multiplication formula */
- /* - The convention for associating quaternions */
- /* with rotation matrices */
- /* Two of the commonly used styles are */
- /* - "SPICE" */
- /* > Invented by Sir William Rowan Hamilton */
- /* > Frequently used in mathematics and physics textbooks */
- /* - "Engineering" */
- /* > Widely used in aerospace engineering applications */
- /* SPICELIB subroutine interfaces ALWAYS use SPICE quaternions. */
- /* Quaternions of any other style must be converted to SPICE */
- /* quaternions before they are passed to SPICELIB routines. */
- /* Relationship between SPICE and Engineering Quaternions */
- /* ------------------------------------------------------ */
- /* Let M be a rotation matrix such that for any vector V, */
- /* M*V */
- /* is the result of rotating V by theta radians in the */
- /* counterclockwise direction about unit rotation axis vector A. */
- /* Then the SPICE quaternions representing M are */
- /* (+/-) ( cos(theta/2), */
- /* sin(theta/2) A(1), */
- /* sin(theta/2) A(2), */
- /* sin(theta/2) A(3) ) */
- /* while the engineering quaternions representing M are */
- /* (+/-) ( -sin(theta/2) A(1), */
- /* -sin(theta/2) A(2), */
- /* -sin(theta/2) A(3), */
- /* cos(theta/2) ) */
- /* For both styles of quaternions, if a quaternion q represents */
- /* a rotation matrix M, then -q represents M as well. */
- /* Given an engineering quaternion */
- /* QENG = ( q0, q1, q2, q3 ) */
- /* the equivalent SPICE quaternion is */
- /* QSPICE = ( q3, -q0, -q1, -q2 ) */
- /* Associating SPICE Quaternions with Rotation Matrices */
- /* ---------------------------------------------------- */
- /* Let FROM and TO be two right-handed reference frames, for */
- /* example, an inertial frame and a spacecraft-fixed frame. Let the */
- /* symbols */
- /* V , V */
- /* FROM TO */
- /* denote, respectively, an arbitrary vector expressed relative to */
- /* the FROM and TO frames. Let M denote the transformation matrix */
- /* that transforms vectors from frame FROM to frame TO; then */
- /* V = M * V */
- /* TO FROM */
- /* where the expression on the right hand side represents left */
- /* multiplication of the vector by the matrix. */
- /* Then if the unit-length SPICE quaternion q represents M, where */
- /* q = (q0, q1, q2, q3) */
- /* the elements of M are derived from the elements of q as follows: */
- /* +- -+ */
- /* | 2 2 | */
- /* | 1 - 2*( q2 + q3 ) 2*(q1*q2 - q0*q3) 2*(q1*q3 + q0*q2) | */
- /* | | */
- /* | | */
- /* | 2 2 | */
- /* M = | 2*(q1*q2 + q0*q3) 1 - 2*( q1 + q3 ) 2*(q2*q3 - q0*q1) | */
- /* | | */
- /* | | */
- /* | 2 2 | */
- /* | 2*(q1*q3 - q0*q2) 2*(q2*q3 + q0*q1) 1 - 2*( q1 + q2 ) | */
- /* | | */
- /* +- -+ */
- /* Note that substituting the elements of -q for those of q in the */
- /* right hand side leaves each element of M unchanged; this shows */
- /* that if a quaternion q represents a matrix M, then so does the */
- /* quaternion -q. */
- /* To map the rotation matrix M to a unit quaternion, we start by */
- /* decomposing the rotation matrix as a sum of symmetric */
- /* and skew-symmetric parts: */
- /* 2 */
- /* M = [ I + (1-cos(theta)) OMEGA ] + [ sin(theta) OMEGA ] */
- /* symmetric skew-symmetric */
- /* OMEGA is a skew-symmetric matrix of the form */
- /* +- -+ */
- /* | 0 -n3 n2 | */
- /* | | */
- /* OMEGA = | n3 0 -n1 | */
- /* | | */
- /* | -n2 n1 0 | */
- /* +- -+ */
- /* The vector N of matrix entries (n1, n2, n3) is the rotation axis */
- /* of M and theta is M's rotation angle. Note that N and theta */
- /* are not unique. */
- /* Let */
- /* C = cos(theta/2) */
- /* S = sin(theta/2) */
- /* Then the unit quaternions Q corresponding to M are */
- /* Q = +/- ( C, S*n1, S*n2, S*n3 ) */
- /* The mappings between quaternions and the corresponding rotations */
- /* are carried out by the SPICELIB routines */
- /* Q2M {quaternion to matrix} */
- /* M2Q {matrix to quaternion} */
- /* M2Q always returns a quaternion with scalar part greater than */
- /* or equal to zero. */
- /* SPICE Quaternion Multiplication Formula */
- /* --------------------------------------- */
- /* Given a SPICE quaternion */
- /* Q = ( q0, q1, q2, q3 ) */
- /* corresponding to rotation axis A and angle theta as above, we can */
- /* represent Q using "scalar + vector" notation as follows: */
- /* s = q0 = cos(theta/2) */
- /* v = ( q1, q2, q3 ) = sin(theta/2) * A */
- /* Q = s + v */
- /* Let Q1 and Q2 be SPICE quaternions with respective scalar */
- /* and vector parts s1, s2 and v1, v2: */
- /* Q1 = s1 + v1 */
- /* Q2 = s2 + v2 */
- /* We represent the dot product of v1 and v2 by */
- /* <v1, v2> */
- /* and the cross product of v1 and v2 by */
- /* v1 x v2 */
- /* Then the SPICE quaternion product is */
- /* Q1*Q2 = s1*s2 - <v1,v2> + s1*v2 + s2*v1 + (v1 x v2) */
- /* If Q1 and Q2 represent the rotation matrices M1 and M2 */
- /* respectively, then the quaternion product */
- /* Q1*Q2 */
- /* represents the matrix product */
- /* M1*M2 */
- /* $ Examples */
- /* 1) A case amenable to checking by hand calculation: */
- /* To convert the quaternion */
- /* Q = ( sqrt(2)/2, 0, 0, -sqrt(2)/2 ) */
- /* to a rotation matrix, we can use the code fragment */
- /* Q(0) = DSQRT(2)/2.D0 */
- /* Q(1) = 0.D0 */
- /* Q(2) = 0.D0 */
- /* Q(3) = -DSQRT(2)/2.D0 */
- /* CALL Q2M ( Q, R ) */
- /* The matrix R will be set equal to */
- /* +- -+ */
- /* | 0 1 0 | */
- /* | | */
- /* | -1 0 0 |. */
- /* | | */
- /* | 0 0 1 | */
- /* +- -+ */
- /* Why? Well, Q represents a rotation by some angle r about */
- /* some axis vector A, where r and A satisfy */
- /* Q = */
- /* ( cos(r/2), sin(r/2)A(1), sin(r/2)A(2), sin(r/2)A(3) ). */
- /* In this example, */
- /* Q = ( sqrt(2)/2, 0, 0, -sqrt(2)/2 ), */
- /* so */
- /* cos(r/2) = sqrt(2)/2. */
- /* Assuming that r is in the interval [0, pi], we must have */
- /* r = pi/2, */
- /* so */
- /* sin(r/2) = sqrt(2)/2. */
- /* Since the second through fourth components of Q represent */
- /* sin(r/2) * A, */
- /* it follows that */
- /* A = ( 0, 0, -1 ). */
- /* So Q represents a transformation that rotates vectors by */
- /* pi/2 about the negative z-axis. This is equivalent to a */
- /* coordinate system rotation of pi/2 about the positive */
- /* z-axis; and we recognize R as the matrix */
- /* [ pi/2 ] . */
- /* 3 */
- /* 2) Finding a set of Euler angles that represent a rotation */
- /* specified by a quaternion: */
- /* Suppose our rotation R is represented by the quaternion */
- /* Q. To find angles TAU, ALPHA, DELTA such that */
- /* R = [ TAU ] [ pi/2 - DELTA ] [ ALPHA ] , */
- /* 3 2 3 */
- /* we can use the code fragment */
- /* CALL Q2M ( Q, R ) */
- /* CALL M2EUL ( R, 3, 2, 3, */
- /* . TAU, DELTA, ALPHA ) */
- /* DELTA = HALFPI() - DELTA */
- /* $ Restrictions */
- /* None. */
- /* $ Literature_References */
- /* [1] NAIF document 179.0, "Rotations and their Habits", by */
- /* W. L. Taber. */
- /* $ Author_and_Institution */
- /* N.J. Bachman (JPL) */
- /* W.L. Taber (JPL) */
- /* F.S. Turner (JPL) */
- /* $ Version */
- /* - SPICELIB Version 1.1.2, 26-FEB-2008 (NJB) */
- /* Updated header; added information about SPICE */
- /* quaternion conventions. */
- /* - SPICELIB Version 1.1.1, 13-JUN-2002 (FST) */
- /* Updated the Exceptions section to clarify exceptions that */
- /* are the result of changes made in the previous version of */
- /* the routine. */
- /* - SPICELIB Version 1.1.0, 04-MAR-1999 (WLT) */
- /* Added code to handle the case in which the input quaternion */
- /* is not of length 1. */
- /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */
- /* Comment section for permuted index source lines was added */
- /* following the header. */
- /* - SPICELIB Version 1.0.0, 30-AUG-1990 (NJB) */
- /* -& */
- /* $ Index_Entries */
- /* quaternion to matrix */
- /* -& */
- /* Local variables */
- /* If a matrix R represents a rotation of r radians about the unit */
- /* vector n, we know that R can be represented as */
- /* 2 */
- /* I + sin(r) N + [ 1 - cos(r) ] N , */
- /* where N is the matrix that satisfies */
- /* Nv = n x v */
- /* for all vectors v, namely */
- /* +- -+ */
- /* | 0 -n n | */
- /* | 3 2 | */
- /* | | */
- /* N = | n 0 -n |. */
- /* | 3 1 | */
- /* | | */
- /* | -n n 0 | */
- /* | 2 1 | */
- /* +- -+ */
- /* Define S as */
- /* sin(r/2) N, */
- /* and let our input quaternion Q be */
- /* ( q , q , q , q ). */
- /* 0 1 2 3 */
- /* Using the facts that */
- /* 2 */
- /* 1 - cos(r) = 2 sin (r/2) */
- /* and */
- /* sin(r) = 2 cos(r/2) sin(r/2), */
- /* we can express R as */
- /* 2 */
- /* I + 2 cos(r/2) S + 2 S, */
- /* or */
- /* 2 */
- /* I + 2 q S + 2 S. */
- /* 0 */
- /* Since S is just */
- /* +- -+ */
- /* | 0 -q q | */
- /* | 3 2 | */
- /* | | */
- /* | q 0 -q |, */
- /* | 3 1 | */
- /* | | */
- /* | -q q 0 | */
- /* | 2 1 | */
- /* +- -+ */
- /* our expression for R comes out to */
- /* +- -+ */
- /* | 2 2 | */
- /* | 1 - 2 ( q + q ) 2( q q - q q ) 2 ( q q + q q ) | */
- /* | 2 3 1 2 0 3 1 3 0 2 | */
- /* | | */
- /* | 2 2 | */
- /* | 2( q q + q q ) 1 - 2 ( q + q ) 2 ( q q - q q ) |. */
- /* | 1 2 0 3 1 3 2 3 0 1 | */
- /* | | */
- /* | 2 2 | */
- /* | 2( q q - q q ) 2 ( q q + q q ) 1 - 2 ( q + q ) | */
- /* | 1 3 0 2 2 3 0 1 1 2 | */
- /* +- -+ */
- /* For efficiency, we avoid duplicating calculations where possible. */
- q01 = q[0] * q[1];
- q02 = q[0] * q[2];
- q03 = q[0] * q[3];
- q12 = q[1] * q[2];
- q13 = q[1] * q[3];
- q23 = q[2] * q[3];
- q1s = q[1] * q[1];
- q2s = q[2] * q[2];
- q3s = q[3] * q[3];
- /* We sharpen the computation by effectively converting Q to */
- /* a unit quaternion if it isn't one already. */
- l2 = q[0] * q[0] + q1s + q2s + q3s;
- if (l2 != 1. && l2 != 0.) {
- sharpn = 1. / l2;
- q01 *= sharpn;
- q02 *= sharpn;
- q03 *= sharpn;
- q12 *= sharpn;
- q13 *= sharpn;
- q23 *= sharpn;
- q1s *= sharpn;
- q2s *= sharpn;
- q3s *= sharpn;
- }
- r__[0] = 1. - (q2s + q3s) * 2.;
- r__[1] = (q12 + q03) * 2.;
- r__[2] = (q13 - q02) * 2.;
- r__[3] = (q12 - q03) * 2.;
- r__[4] = 1. - (q1s + q3s) * 2.;
- r__[5] = (q23 + q01) * 2.;
- r__[6] = (q13 + q02) * 2.;
- r__[7] = (q23 - q01) * 2.;
- r__[8] = 1. - (q1s + q2s) * 2.;
- return 0;
- } /* q2m_ */