anim.c

Go to the documentation of this file.
00001 /*                          A N I M . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1993-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 /** \addtogroup anim */
00022 /*@{*/
00023 /** @file anim.c
00024  * @brief
00025  *      Routines useful in animation programs.
00026  *
00027  *  @author
00028  *      Carl J. Nuzman
00029  *
00030  *  @par Source -
00031  *      The U. S. Army Research Laboratory
00032  *@n      Aberdeen Proving Ground, Maryland  21005-5068  USA
00033  *
00034  *
00035  *
00036  *
00037  ***********************************************************************
00038  *
00039  * @par This file includes the following routines:
00040  * @li anim_v_permute() apply camera animation permutation
00041  * @li anim_v_unpermute()       undo camera animation permutation
00042  * @li anim_tran()              transpose matrix in place
00043  * @li anim_mat2zyx()           extract angles from rotation matrix
00044  * @li anim_mat2ypr()           extract yaw,pitch,roll from rotation matrix
00045  * @li anim_mat2quat()          extract quaternion from rotation matrix
00046  * @li anim_ypr2mat()           create rotation matrix from ypr, etc.
00047  * @li anim_ypr2vmat()
00048  * @li anim_y_p_r2mat()
00049  * @li anim_dy_p_r2mat()
00050  * @li anim_dy_p_r2vmat()
00051  * @li anim_x_y_z2mat()
00052  * @li anim_dx_y_z2mat()
00053  * @li anim_z_y_x2mat()
00054  * @li anim_dz_y_x2mat()
00055  * @li anim_quat2mat()
00056  * @li anim_dir2mat()           create rotation matrix from direction
00057  * @li anim_dirn2mat()          create rot matrix from dir and normal
00058  * @li anim_steer_mat() automatic steering
00059  * @li anim_add_trans() add pre- and post- translation to matrix
00060  * @li anim_rotatez()           rotate vector about z-axis
00061  * @li anim_mat_print() print matrix with optional semi-colon
00062  * @li anim_view_rev()          reverse view matrix
00063  */
00064 
00065 
00066 #include "common.h"
00067 
00068 #include <stdio.h>
00069 #include <math.h>
00070 #include "machine.h"
00071 #include "bu.h"
00072 #include "vmath.h"
00073 #include "bn.h"
00074 #include "anim.h"
00075 
00076 #ifndef M_PI
00077 #define M_PI    3.14159265358979323846
00078 #endif
00079 
00080 #define NORMAL          0
00081 #define ERROR1          1
00082 #define ERROR2          2
00083 
00084 
00085 /**
00086  *  Orientation conventions:
00087  * The default object orientation is facing the positive x-axis, with
00088  * the positive y-axis to the object's left and the positive z-axis above
00089  * the object.
00090  * The default view orientation for rt and mged is facing the negative z-axis,
00091  * with the negative x-axis leading to the left and the positive y-axis
00092  * going upwards.
00093  */
00094 
00095 /**
00096  *  ANIM_V_PERMUTE 
00097  * @brief Pre-multiply a rotation matrix by a matrix
00098  * which maps the z-axis to the negative x-axis, the y-axis to the
00099  * z-axis and the x-axis to the negative y-axis.
00100  *
00101  * This has the effect of twisting an object in the default view orientation
00102  * into the default object orientation before applying the matrix.
00103  * Given a matrix designed to operate on an object, yield a matrix which
00104  * operates on the view.
00105  */
00106 void anim_v_permute(mat_t m)
00107 {
00108         int i;
00109         fastf_t store;
00110 
00111         for (i=0; i<9; i+=4){
00112                 store = m[i];
00113                 m[i] = -m[i+1];
00114                 m[i+1] = m[i+2];
00115                 m[i+2] = -store;
00116         }
00117 }
00118 
00119 /**
00120  *  ANIM_V_UNPERMUTE 
00121  * @brief Undo the mapping done by anim_v_permute().
00122  *
00123  * This has the effect of twisting an object in the default object
00124  * orientation into the default view orientation before applying the
00125  * matrix.
00126  * Given a matrix designed to operate on the view, yield a matrix which
00127  * operates on an object.
00128  */
00129 void anim_v_unpermute(mat_t m)
00130 {
00131         int i;
00132         fastf_t store;
00133 
00134         for (i=0; i<9; i+=4){
00135                 store = m[i+2];
00136                 m[i+2] = m[i+1];
00137                 m[i+1] = -m[i];
00138                 m[i] = -store;
00139         }
00140 }
00141 
00142 /** @brief Transpose matrix in place */
00143 void anim_tran(mat_t m)
00144 {
00145         int i;
00146         fastf_t store;
00147 #if 1
00148         /* The sun4's complain about no automatic aggregate initialization,
00149          * so we'll do it another way. :-(
00150          */
00151         int src[6];
00152         int dst[6];
00153 
00154         src[0] = 1;
00155         src[1] = 2;
00156         src[2] = 3;
00157         src[3] = 6;
00158         src[4] = 7;
00159         src[5] = 11;
00160 
00161         dst[0] = 4;
00162         dst[1] = 8;
00163         dst[2] = 12;
00164         dst[3] = 9;
00165         dst[4] = 13;
00166         dst[5] = 14;
00167 #else
00168         int src[] = { 1, 2, 3, 6, 7, 11 };
00169         int dst[] = { 4, 8, 12, 9, 13, 14};
00170 #endif
00171 
00172         for (i=0; i<6; i++) {
00173                 store = m[dst[i]];
00174                 m[dst[i]] = m[src[i]];
00175                 m[src[i]] = store;
00176         }
00177 }
00178 
00179 /***************************************
00180  *ANIM_MAT2* - Conversions from matrices
00181  ***************************************/
00182 
00183 /** ANIM_MAT2ZYX 
00184  * @brief
00185  *  Convert the rotational part of a 4x4 transformation matrix
00186  * to zyx form, that is to say, rotations carried out in the order z, y,
00187  * and then x. The angles are stored in radians as a vector in the order
00188  * x,y,z. A return value of ERROR1 means that arbitrary assumptions were
00189  * necessary. ERROR2 means that the conversion failed.
00190  */
00191 int anim_mat2zyx(const mat_t viewrot, vect_t angle)
00192 {
00193         int i, return_value, id_x, id_z;
00194         fastf_t sin_x, sin_z, cos_x, cos_z, big_x, big_z;
00195         static fastf_t previous[3];
00196 
00197         if ((viewrot[1]==0.0) && (viewrot[0]==0.0)){
00198                 return_value = ERROR1;
00199                 angle[0] = 0.0;
00200                 angle[2] = atan2(viewrot[4],viewrot[5]);
00201                 /*bu_log("Warning: x arbitrarily set to 0.0; z set to %f.\n",angle[2]);*/
00202         }
00203         else {
00204                 return_value = NORMAL;
00205                 angle[2] = atan2(-viewrot[1],viewrot[0]);
00206                 angle[0] = atan2(-viewrot[6],viewrot[10]);
00207         }
00208 
00209         sin_x = sin(angle[0]);
00210         sin_z = sin(angle[2]);
00211         cos_x = cos(angle[0]);
00212         cos_z = cos(angle[2]);
00213 
00214         /* in principle, we can use the sin_x or cos_x with sin_z or cos_z to
00215          * figure out angle[1], as long as they are non-zero. To avoid
00216          * ill-conditioning effects, we choose the two that are greatest in
00217          * absolute value
00218          */
00219 
00220         id_z  = (fabs(sin_z) > fabs(cos_z)) ? 1 : 0;
00221         big_z = id_z ? sin_z : cos_z;
00222         id_x  = (fabs(sin_x) > fabs(cos_x)) ? 1 : 0;
00223         big_x = id_x ? sin_x : cos_x;
00224 
00225         if (fabs(big_x*big_z) < VDIVIDE_TOL){ /* this should be impossible*/
00226                 /* unable to calculate pitch*/
00227                 return(ERROR2);
00228         }
00229         else if ( id_x && (!id_z) )
00230                 angle[1]=atan2( (viewrot[4] - cos_x*sin_z)/(sin_x*cos_z), -viewrot[6]/sin_x);
00231         else if ( (!id_x) && (!id_z) )
00232                 angle[1]=atan2( (-viewrot[8] + sin_x*sin_z)/(cos_x*cos_z), viewrot[0]/cos_z);
00233         else if ( id_x && id_z )
00234                 angle[1]=atan2( (-viewrot[5] + cos_x*cos_z)/(sin_x*sin_z), -viewrot[1]/sin_z);
00235         else if ( (!id_x) && id_z )
00236                 angle[1]=atan2( (viewrot[9] - sin_x*cos_z)/(cos_x*sin_z), viewrot[10]/cos_x);
00237 
00238 
00239         /* assume the smallest possible arc-length from frame to frame */
00240         for (i=0; i<3; i++) {
00241                 while ((angle[i] - previous[i]) > M_PI)
00242                         angle[i] -= (2.0*M_PI);
00243                 while ((previous[i] - angle[i]) > M_PI)
00244                         angle[i] += (2.0*M_PI);
00245                 previous[i] = angle[i];
00246         }
00247 
00248         return(return_value);
00249 }
00250 
00251 /** ANIM_MAT2YPR 
00252  *@brief
00253  * Convert the rotational part of a 4x4 transformation matrix
00254  * to yaw-pitch-roll form, that is to say, +roll degrees about the x-axis,
00255  * -pitch degrees about the y-axis, and +yaw degrees about the
00256  * z-axis. The angles are stored in radians as a vector in the order y,p,r.
00257  * A return of ERROR1 means that arbitrary assumptions were necessary.
00258  * ERROR2 means that the conversion failed.
00259  */
00260 int anim_mat2ypr(mat_t viewrot, vect_t angle)
00261 {
00262         int i, return_value, id_y, id_r;
00263         fastf_t sin_y, sin_r, cos_y, cos_r, big_y, big_r;
00264         static fastf_t prev_angle[3];
00265 
00266         if ((viewrot[9]==0.0) && (viewrot[10]==0.0)){
00267                 return_value = ERROR1;
00268                 angle[2] = 0.0;
00269                 angle[0] = atan2(-viewrot[1],viewrot[5]);
00270                 /*bu_log("Warning: roll arbitrarily set to 0.0; yaw set to %f radians.\n",angle[0]);*/
00271         }
00272         else {
00273                 return_value = NORMAL;
00274                 angle[0] = atan2(viewrot[4],viewrot[0]);
00275                 angle[2] = atan2(viewrot[9],viewrot[10]);
00276         }
00277 
00278         sin_y = sin(angle[0]);
00279         sin_r = sin(angle[2]);
00280         cos_y = cos(angle[0]);
00281         cos_r = cos(angle[2]);
00282 
00283         /* in principle, we can use sin_y or cos_y with sin_r or cos_r to
00284          * figure out angle[1], as long as they are non-zero. To avoid
00285          * ill-conditioning effects, we choose the two that are greatest in
00286          * absolute value
00287          */
00288 
00289         id_y  = (fabs(sin_y) > fabs(cos_y)) ? 1 : 0;
00290         big_y = id_y ? sin_y : cos_y;
00291         id_r  = (fabs(sin_r) > fabs(cos_r)) ? 1 : 0;
00292         big_r = id_r ? sin_r : cos_r;
00293 
00294         if (fabs(big_y*big_r) < VDIVIDE_TOL){ /* this should not happen */
00295                 /* unable to calculate pitch*/
00296                 return(ERROR2);
00297         }
00298         else if ( (!id_y) && id_r )
00299                 angle[1] = atan2( -(viewrot[1]+sin_y*cos_r)/(cos_y*sin_r),viewrot[9]/sin_r);
00300         else if ( id_y && (!id_r) )
00301                 angle[1] = atan2( -(viewrot[6]+cos_y*sin_r)/(sin_y*cos_r),viewrot[10]/cos_r);
00302         else if ( id_y && id_r )
00303                 angle[1] = atan2( -(viewrot[5]-cos_y*cos_r)/(sin_y*sin_r),viewrot[4]/sin_y);
00304         else if ( (!id_y) && (!id_r) )
00305                 angle[1] = atan2( -(viewrot[2]-sin_y*sin_r)/(cos_y*cos_r),viewrot[0]/cos_y);
00306 
00307 
00308         /* assume the smallest possible arc-length from frame to frame */
00309         for (i=0; i<3; i++) {
00310                 while ((angle[i] - prev_angle[i]) > M_PI)
00311                         angle[i] -= (2.0*M_PI);
00312                 while ((prev_angle[i] - angle[i]) > M_PI)
00313                         angle[i] += (2.0*M_PI);
00314                 prev_angle[i] = angle[i];
00315         }
00316 
00317         return(return_value);
00318 }
00319 
00320 /** ANIM_MAT2QUAT 
00321  * @brief
00322  * This interprets the rotational part of a 4x4 transformation
00323  *  matrix in terms of unit quaternions. The result is stored as a vector in
00324  * the order x,y,z,w.
00325  * The algorithm is from Ken Shoemake, Animating Rotation with Quaternion
00326  * Curves, 1985 SIGGraph Conference Proceeding, p.245.
00327  */
00328 int anim_mat2quat(quat_t quat, const mat_t viewrot)
00329 {
00330         int i;
00331         fastf_t qdiff[4], square, mag1, mag2;
00332         static fastf_t prev_quat[4];
00333 
00334         square = 0.25 * (1 + viewrot[0] + viewrot[5] + viewrot[10]);
00335         if ( square != 0.0 ) {
00336                 quat[W] = sqrt(square);
00337                 quat[X] = 0.25 * (viewrot[9] - viewrot[6])/ quat[W];
00338                 quat[Y] = 0.25 * (viewrot[2] - viewrot[8])/ quat[W];
00339                 quat[Z] = 0.25 * (viewrot[4] - viewrot[1])/ quat[W];
00340         }
00341         else {
00342                 quat[W] = 0.0;
00343                 square = -0.5 * (viewrot[5] + viewrot[10]);
00344                 if (square != 0.0 ) {
00345                         quat[X] = sqrt(square);
00346                         quat[Y] = 0.5 * viewrot[4] / quat[X];
00347                         quat[Z] = 0.5 * viewrot[8] / quat[X];
00348                 }
00349                 else {
00350                         quat[X] = 0.0;
00351                         square = 0.5 * (1 - viewrot[10]);
00352                         if (square != 0.0){
00353                                 quat[Y] = sqrt(square);
00354                                 quat[Z] = 0.5 * viewrot[9]/ quat[Y];
00355                         }
00356                         else {
00357                                 quat[Y] = 0.0;
00358                                 quat[Z] = 1.0;
00359                         }
00360                 }
00361         }
00362 
00363         /* quaternions on opposite sides of a four-dimensional sphere
00364                 are equivalent. Take the quaternion closest to the previous
00365                 one */
00366 
00367         for (i=0; i<4; i++)
00368                 qdiff[i] = prev_quat[i] - quat[i];
00369         mag1 = QMAGSQ(qdiff);
00370         for (i=0; i<4; i++)
00371                 qdiff[i] = prev_quat[i] + quat[i];
00372         mag2 = QMAGSQ(qdiff);
00373 
00374         for (i=0; i<4; i++) {
00375                 if (mag1 > mag2)  /* inverse of quat would be closer */
00376                         quat[i] = -quat[i];
00377                 prev_quat[i] = quat[i];
00378         }
00379 
00380         return(1);
00381 }
00382 
00383 /***************************************
00384  *ANIM_*2MAT - Conversions to matrices
00385  ***************************************/
00386 
00387 /** ANIM_YPR2MAT 
00388  * @brief Create a premultiplication rotation matrix to turn the front
00389  * of an object (its x-axis) to the given yaw, pitch, and roll,
00390  * which is stored in radians in the vector a.
00391  */
00392 void anim_ypr2mat(mat_t m, const vect_t a)
00393 {
00394         fastf_t cos_y,cos_p,cos_r,sin_y,sin_p,sin_r;
00395 
00396         cos_y = cos(a[0]);
00397         cos_p = cos(a[1]);
00398         cos_r = cos(a[2]);
00399         sin_y = sin(a[0]);
00400         sin_p = sin(a[1]);
00401         sin_r = sin(a[2]);
00402 
00403         m[0] =   cos_y*cos_p;
00404         m[1] =   -cos_y*sin_p*sin_r-sin_y*cos_r;
00405         m[2] =   -cos_y*sin_p*cos_r+sin_y*sin_r;
00406         m[3] =  0;
00407         m[4] =  sin_y*cos_p;
00408         m[5] =  -sin_y*sin_p*sin_r+cos_y*cos_r;
00409         m[6] =  -sin_y*sin_p*cos_r-cos_y*sin_r;
00410         m[7] =  0;
00411         m[8]=   sin_p;
00412         m[9] =  cos_p*sin_r;
00413         m[10] = cos_p*cos_r;
00414         m[11] = 0.0;
00415         m[12] = 0.0;
00416         m[13] = 0.0;
00417         m[14] = 0.0;
00418         m[15] = 1.0;
00419 }
00420 
00421 /** ANIM_YPR2VMAT 
00422  * @brief Create a post-multiplication rotation matrix ,which could
00423  * be used to move the virtual camera to the given yaw, pitch,
00424  * and roll,  which are stored in radians in the given vector a. The
00425  * following are equivalent sets of commands:
00426  *      ypr2vmat(matrix,a);
00427  *              or
00428  *      ypr2mat(matrix,a);
00429  *      v_permute(matrix);
00430  *      transpose(matrix;
00431  */
00432 void anim_ypr2vmat(mat_t m, const vect_t a)
00433 {
00434         fastf_t cos_y,cos_p,cos_r,sin_y,sin_p,sin_r;
00435 
00436         cos_y = cos(a[0]);
00437         cos_p = cos(a[1]);
00438         cos_r = cos(a[2]);
00439         sin_y = sin(a[0]);
00440         sin_p = sin(a[1]);
00441         sin_r = sin(a[2]);
00442 
00443         m[0] =    -cos_y*sin_p*sin_r-sin_y*cos_r;
00444         m[1] =    -sin_y*sin_p*sin_r+cos_y*cos_r;
00445         m[2] =     cos_p*sin_r;
00446         m[3] =     0;
00447         m[4] =    -cos_y*sin_p*cos_r+sin_y*sin_r;
00448         m[5] =    -sin_y*sin_p*cos_r-cos_y*sin_r;
00449         m[6] =     cos_p*cos_r;
00450         m[7] =     0;
00451         m[8] =     cos_y*cos_p;
00452         m[9] =     sin_y*cos_p;
00453         m[10] =    sin_p;
00454         m[11] =    0.0;
00455         m[12] =    0.0;
00456         m[13] =    0.0;
00457         m[14] =    0.0;
00458         m[15] =    1.0;
00459 }
00460 
00461 /** ANIM_Y_P_R2MAT 
00462  * @brief
00463  * Make matrix to rotate an object to the given yaw,
00464  * pitch, and roll. (Specified in radians.)
00465  */
00466 void anim_y_p_r2mat(mat_t m, double y, double p, double r)
00467 {
00468         fastf_t cos_y = cos(y);
00469         fastf_t sin_y = sin(y);
00470         fastf_t cos_p = cos(p);
00471         fastf_t sin_p = sin(p);
00472         fastf_t cos_r = cos(r);
00473         fastf_t sin_r = sin(r);
00474 
00475         m[0] = cos_y*cos_p;
00476         m[1] = -cos_y*sin_p*sin_r-sin_y*cos_r;
00477         m[2] = -cos_y*sin_p*cos_r+sin_y*sin_r;
00478         m[4] = sin_y*cos_p;
00479         m[5] = -sin_y*sin_p*sin_r+cos_y*cos_r;
00480         m[6] = -sin_y*sin_p*cos_r-cos_y*sin_r;
00481         m[8]= sin_p;
00482         m[9] = cos_p*sin_r;
00483         m[10] = cos_p*cos_r;
00484         m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0;
00485         m[15]=1;
00486 }
00487 
00488 
00489 
00490 
00491 /** ANIM_DY_P_R2MAT
00492  * @brief Make matrix to rotate an object to the given yaw,
00493  * pitch, and roll. (Specified in degrees.)
00494  */
00495 void anim_dy_p_r2mat(mat_t m, double y, double p, double r)
00496 {
00497         fastf_t radian_yaw = y*(M_PI*0.0055555555556);
00498         fastf_t radian_pitch = p*(M_PI*0.0055555555556);
00499         fastf_t radian_roll = r*(M_PI*0.0055555555556);
00500 
00501         fastf_t cos_y = cos(radian_yaw);
00502         fastf_t sin_y = sin(radian_yaw);
00503         fastf_t cos_p = cos(radian_pitch);
00504         fastf_t sin_p = sin(radian_pitch);
00505         fastf_t cos_r = cos(radian_roll);
00506         fastf_t sin_r = sin(radian_roll);
00507 
00508         m[0] = cos_y*cos_p;
00509         m[1] = -cos_y*sin_p*sin_r-sin_y*cos_r;
00510         m[2] = -cos_y*sin_p*cos_r+sin_y*sin_r;
00511         m[4] = sin_y*cos_p;
00512         m[5] = -sin_y*sin_p*sin_r+cos_y*cos_r;
00513         m[6] = -sin_y*sin_p*cos_r-cos_y*sin_r;
00514         m[8]= sin_p;
00515         m[9] = cos_p*sin_r;
00516         m[10] = cos_p*cos_r;
00517         m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0;
00518         m[15]=1;
00519 }
00520 
00521 
00522 /** ANIM_DY_P_R2VMAT
00523  * @brief  Make a view rotation matrix, given desired yaw, pitch
00524  * and roll. (Note that the matrix is a permutation of the object rotation
00525  * matrix).
00526  */
00527 void anim_dy_p_r2vmat(mat_t m, double yaw, double pch, double rll)
00528 {
00529 
00530         float ryaw = yaw*(M_PI*0.0055555555556);
00531         float rpch = pch*(M_PI*0.0055555555556);
00532         float rrll = rll*(M_PI*0.0055555555556);
00533 
00534         float cos_y = cos(ryaw);
00535         float sin_y = sin(ryaw);
00536         float cos_p = cos(rpch);
00537         float sin_p = sin(rpch);
00538         float cos_r = cos(rrll);
00539         float sin_r = sin(rrll);
00540 
00541         m[0] = -cos_y*sin_p*sin_r-sin_y*cos_r;
00542         m[1] = -sin_y*sin_p*sin_r+cos_y*cos_r;
00543         m[2] = cos_p*sin_r;
00544         m[4] = -cos_y*sin_p*cos_r+sin_y*sin_r;
00545         m[5] = -sin_y*sin_p*cos_r-cos_y*sin_r;
00546         m[6] = cos_p*cos_r;
00547         m[8] = cos_y*cos_p;
00548         m[9] = sin_y*cos_p;
00549         m[10]= sin_p;
00550         m[3]=m[7]=m[11]=0;
00551         m[12]=m[13]=m[14]=0;
00552         m[15]=1;
00553 
00554 }
00555 
00556 /** ANIM_X_Y_Z2MAT 
00557  * @brief Make a rotation matrix corresponding to a rotation of
00558  * "x" radians about the x-axis, "y" radians about the y-axis, and
00559  * then "z" radians about the z-axis.
00560  */
00561 void anim_x_y_z2mat(mat_t m, double x, double y, double z)
00562 {
00563         fastf_t cosx = cos(x);
00564         fastf_t sinx = sin(x);
00565         fastf_t cosy = cos(y);
00566         fastf_t siny = sin(y);
00567         fastf_t cosz = cos(z);
00568         fastf_t sinz = sin(z);
00569 
00570         m[0] = cosz*cosy;
00571         m[1] = cosz*siny*sinx-sinz*cosx;
00572         m[2] = cosz*siny*cosx+sinz*sinx;
00573         m[4] = sinz*cosy;
00574         m[5] = sinz*siny*sinx+cosz*cosx;
00575         m[6] = sinz*siny*cosx-cosz*sinx;
00576         m[8] = -siny;
00577         m[9] = cosy*sinx;
00578         m[10] = cosy*cosx;
00579         m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0;
00580         m[15]=1;
00581 }
00582 
00583 
00584 
00585 /** ANIM_DX_Y_Z2MAT 
00586  * @brief Make a rotation matrix corresponding to a rotation of
00587  * "x" degrees about the x-axis, "y" degrees about the y-axis, and
00588  * then "z" degrees about the z-axis.
00589  */
00590 void anim_dx_y_z2mat(mat_t m, double x, double y, double z)
00591 {
00592         fastf_t cosx,cosy,cosz,sinx,siny,sinz;
00593 
00594         x *= (M_PI*0.0055555555556);
00595         y *= (M_PI*0.0055555555556);
00596         z *= (M_PI*0.0055555555556);
00597 
00598         cosx = cos(x);
00599         sinx = sin(x);
00600         cosy = cos(y);
00601         siny = sin(y);
00602         cosz = cos(z);
00603         sinz = sin(z);
00604 
00605         m[0] = cosz*cosy;
00606         m[1] = cosz*siny*sinx-sinz*cosx;
00607         m[2] = cosz*siny*cosx+sinz*sinx;
00608         m[4] = sinz*cosy;
00609         m[5] = sinz*siny*sinx+cosz*cosx;
00610         m[6] = sinz*siny*cosx-cosz*sinx;
00611         m[8] = -siny;
00612         m[9] = cosy*sinx;
00613         m[10] = cosy*cosx;
00614         m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0.0;
00615         m[15]=1.0;
00616 }
00617 
00618 /* ANIM_ZYX2MAT @brief Make a rotation matrix corresponding to a rotation of
00619  * "z" radians about the z-axis, "y" radians about the y-axis, and
00620  * then "x" radians about the x-axis.
00621  */
00622 void anim_zyx2mat(mat_t m, const vect_t a)
00623 {
00624         fastf_t cosX,cosY,cosZ,sinX,sinY,sinZ;
00625 
00626         cosX = cos(a[0]);
00627         cosY = cos(a[1]);
00628         cosZ = cos(a[2]);
00629         sinX = sin(a[0]);
00630         sinY = sin(a[1]);
00631         sinZ = sin(a[2]);
00632 
00633         m[0] =     cosY*cosZ;
00634         m[1] =    -cosY*sinZ;
00635         m[2] =     sinY;
00636         m[3] =     0;
00637         m[4] =     cosX*sinZ + sinX*sinY*cosZ;
00638         m[5] =     cosX*cosZ - sinX*sinY*sinZ;
00639         m[6] =    -sinX*cosY;
00640         m[7] =     0;
00641         m[8] =     sinX*sinZ - cosX*sinY*cosZ;
00642         m[9] =     sinX*cosZ + cosX*sinY*sinZ;
00643         m[10] =    cosX*cosY;
00644         m[11] =    0.0;
00645         m[12] =    0.0;
00646         m[13] =    0.0;
00647         m[14] =    0.0;
00648         m[15] =    1.0;
00649 
00650 }
00651 
00652 /** ANIM_Z_Y_X2MAT @brief Make a rotation matrix corresponding to a rotation of
00653  * "z" radians about the z-axis, "y" radians about the y-axis, and
00654  * then "x" radians about the x-axis.
00655  */
00656 void anim_z_y_x2mat(mat_t m, double x, double y, double z)
00657 {
00658         fastf_t cosx = cos(x);
00659         fastf_t sinx = sin(x);
00660         fastf_t cosy = cos(y);
00661         fastf_t siny = sin(y);
00662         fastf_t cosz = cos(z);
00663         fastf_t sinz = sin(z);
00664 
00665         m[0] =  cosy*cosz;
00666         m[1] = -cosy*sinz;
00667         m[2] =  siny;
00668         m[4] =  cosx*sinz + sinx*siny*cosz;
00669         m[5] =  cosx*cosz - sinx*siny*sinz;
00670         m[6] = -sinx*cosy;
00671         m[8] =  sinx*sinz - cosx*siny*cosz;
00672         m[9] =  sinx*cosz + cosx*siny*sinz;
00673         m[10]=  cosx*cosy;
00674         m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0.0;
00675         m[15]=1.0;
00676 }
00677 
00678 
00679 /** ANIM_DZ_Y_X2MAT 
00680  * @brief 
00681  * Make a rotation matrix corresponding to a rotation of
00682  * "z" degrees about the z-axis, "y" degrees about the y-axis, and
00683  * then "x" degrees about the x-axis.
00684  */
00685 void anim_dz_y_x2mat(mat_t m, double x, double y, double z)
00686 {
00687         fastf_t cosx,cosy,cosz,sinx,siny,sinz;
00688 
00689         x *= (M_PI*0.0055555555556);
00690         y *= (M_PI*0.0055555555556);
00691         z *= (M_PI*0.0055555555556);
00692 
00693         cosx = cos(x);
00694         sinx = sin(x);
00695         cosy = cos(y);
00696         siny = sin(y);
00697         cosz = cos(z);
00698         sinz = sin(z);
00699 
00700         m[0] =  cosy*cosz;
00701         m[1] = -cosy*sinz;
00702         m[2] =  siny;
00703         m[4] =  cosx*sinz + sinx*siny*cosz;
00704         m[5] =  cosx*cosz - sinx*siny*sinz;
00705         m[6] = -sinx*cosy;
00706         m[8] =  sinx*sinz - cosx*siny*cosz;
00707         m[9] =  sinx*cosz + cosx*siny*sinz;
00708         m[10]=  cosx*cosy;
00709         m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0;
00710         m[15]=1;
00711 }
00712 
00713 
00714 /* ANIM_QUAT2MAT 
00715  * @brief
00716  *  Make 4x4 matrix from the given quaternion
00717  * Note: these quaternions are the conjugates of the quaternions
00718  * used in the librt/qmath.c quat_quat2mat()
00719  */
00720 
00721 void anim_quat2mat(mat_t m, const quat_t qq)
00722 {
00723         fastf_t two_q[4];
00724         quat_t q;
00725 
00726         QMOVE(q, qq);
00727         QUNITIZE(q);
00728 
00729         VADD2N(two_q,q,q,4);
00730 
00731         m[0]    = 1.0 - two_q[Y]*q[Y] - two_q[Z]*q[Z];
00732         m[1]    = two_q[X]*q[Y] - two_q[W]*q[Z];
00733         m[2]    = two_q[X]*q[Z] + two_q[W]*q[Y];
00734         m[3]    = 0.0;
00735         m[4]    = two_q[X]*q[Y] + two_q[W]*q[Z];
00736         m[5]    = 1.0 - two_q[X]*q[X] - two_q[Z]*q[Z];
00737         m[6]    = two_q[Y]*q[Z] - two_q[W]*q[X];
00738         m[7]    = 0.0;
00739         m[8]    = two_q[X]*q[Z] - two_q[W]*q[Y];
00740         m[9]    = two_q[Y]*q[Z] + two_q[W]*q[X];
00741         m[10]   = 1.0 - two_q[X]*q[X] - two_q[Y]*q[Y];
00742         m[11]   = 0.0;
00743         m[12]   = 0.0;
00744         m[13]   = 0.0;
00745         m[14]   = 0.0;
00746         m[15]   = 1.0;
00747 }
00748 
00749 
00750 
00751 /* ANIM_DIR2MAT 
00752  * @brief
00753  *  make a matrix which turns a vehicle from the x-axis to
00754  * point in the desired direction, staying "right-side up" (ie the y-axis
00755  * never has a z-component). A second direction vector is consulted when
00756  * the given direction is vertical. This is intended to represent the
00757  * the direction from a previous frame.
00758  */
00759 void anim_dir2mat(mat_t m, const vect_t d, const vect_t d2b)
00760 {
00761         fastf_t hypotenuse, sign;
00762         vect_t d2;
00763 
00764         VMOVE( d2, d2b );
00765         sign = 1.0;
00766         hypotenuse = sqrt(d[0]*d[0]+d[1]*d[1]);
00767         if (hypotenuse < VDIVIDE_TOL){ /* vertical direction - use d2 to
00768                                         * determine roll */
00769                 hypotenuse = sqrt(d2[0]*d2[0]+d2[1]*d2[1]);
00770                 if (hypotenuse < VDIVIDE_TOL){ /* use x-axis as default*/
00771                         VSET(d2,1,0,0);
00772                         hypotenuse = 1;
00773                 }
00774                 if (d[2] < 0)
00775                         sign = -1.0;
00776                 m[1] = -d2[1]/hypotenuse;
00777                 m[5] = d2[0]/hypotenuse;
00778                 m[2] = -sign * d2[0]/hypotenuse;
00779                 m[6] = -sign * d2[1]/hypotenuse;
00780                 m[8] = sign;
00781                 m[0]=m[4]=m[9]=m[10]=0.0;
00782         }
00783         else { /* normal - no roll*/
00784                 m[0] = d[0];
00785                 m[1] = -d[1]/hypotenuse;
00786                 m[2] = -d[0]*d[2]/hypotenuse;
00787                 m[4] = d[1];
00788                 m[5] = d[0]/hypotenuse;
00789                 m[6] = -d[1]*d[2]/hypotenuse;
00790                 m[8] = d[2];
00791                 m[9] = 0.0;
00792                 m[10] = hypotenuse;
00793         }
00794         m[3]=m[7]=m[11]=0.0;
00795         m[12]=m[13]=m[14]=0.0;
00796         m[15]=1.0;
00797 
00798 }
00799 
00800 /* ANIM_DIRN2MAT 
00801  * @brief
00802  *  make a matrix which turns a vehicle from the x-axis to
00803  * point in the desired direction, staying "right-side up". In cases where
00804  * the direction is vertical, the second vector is consulted. The second
00805  * vector defines a normal to the the vertical plane into which the vehicle's
00806  * x and z axes should be put. A good choice to put here is the direction
00807  * of the vehicle's y-axis in the previous frame.
00808  */
00809 void anim_dirn2mat(mat_t m, const vect_t dx2, const vect_t dn)
00810 {
00811         vect_t temp;
00812         fastf_t hyp, sign,inv,mag;
00813         vect_t dx;
00814 
00815         VMOVE( dx, dx2 );
00816         sign = 1.0;
00817         mag = MAGNITUDE(dx);
00818         if (mag < VDIVIDE_TOL) {
00819                 bu_log("anim_dirn2mat: Need non-zero vector");
00820                 return;
00821         }
00822         inv = 1.0/mag;
00823         dx[0] *= inv;
00824         dx[1] *= inv;
00825         dx[2] *= inv;
00826         hyp = sqrt(dx[0]*dx[0]+dx[1]*dx[1]);
00827         if (hyp < VDIVIDE_TOL) { /* vertical - special handling */
00828                 sign = (dx[2] < 0) ? -1.0 : 1.0;
00829                 VSET(temp, dn[0], dn[1], 0.0);
00830                 mag = MAGNITUDE(temp);
00831                 if (mag < VDIVIDE_TOL) {
00832                         /* use default */
00833                         VSET(temp, 0.0, 1.0, 0.0);
00834                         mag = 1.0;
00835                 } else {
00836                         inv = 1.0/mag;
00837                         temp[0] *= inv;
00838                         temp[1] *= inv;
00839                 }
00840                 m[0] = 0.0;
00841                 m[4] = 0.0;
00842                 m[8] = sign;
00843                 m[1] = temp[0];
00844                 m[5] = temp[1];
00845                 m[9] = 0.0;
00846                 m[2] = -sign*temp[1];
00847                 m[6] = sign*temp[0];
00848                 m[10] = 0.0;
00849                 m[3]=m[7]=m[11]=0.0;
00850                 m[12]=m[13]=m[14]=0.0;
00851                 m[15]=1.0;
00852                 return;
00853         }
00854 
00855         /*else normal*/
00856         m[0] = dx[0];
00857         m[1] = -dx[1]/hyp;
00858         m[2] = -dx[0]*dx[2]/hyp;
00859         m[4] = dx[1];
00860         m[5] = dx[0]/hyp;
00861         m[6] = -dx[1]*dx[2]/hyp;
00862         m[8] = dx[2];
00863         m[9] = 0.0;
00864         m[10] = hyp;
00865         m[3]=m[7]=m[11]=0.0;
00866         m[12]=m[13]=m[14]=0.0;
00867         m[15]=1.0;
00868 
00869 }
00870 
00871 
00872 
00873 #define ASM_EMPTY 0
00874 #define ASM_FIRST 1
00875 #define ASM_FULL  2
00876 
00877 /*ANIM_STEER_MAT 
00878  * @brief
00879  *  given the next frame's position, remember the value of
00880 the previous frame's position and calculate a matrix which points the x-axis
00881 in the direction defined by those two positions. Return new matrix, and the
00882 remembered value of the current position, as arguments; return 1 as the
00883 normal value, and 0 when there is not yet information to remember.
00884 */
00885 int anim_steer_mat(mat_t  mat, vect_t point, int end)
00886 {
00887         static vect_t p1, p2, p3;
00888         vect_t dir;
00889         static vect_t norm;
00890         static int state = ASM_EMPTY;
00891 
00892         VMOVE(p1,p2);
00893         VMOVE(p2,p3);
00894         VMOVE(p3,point);
00895 
00896         switch(state) {
00897         case ASM_EMPTY:
00898                 if (end) {
00899                         state = ASM_EMPTY;
00900                 } else {
00901                         state = ASM_FIRST;
00902                         /* "don't print yet */
00903                 }
00904                 return 0;
00905         case ASM_FIRST:
00906                 if (end) {
00907                         /* only one point specified, use default direction*/
00908                         VSET(dir,1.0,0.0,0.0);
00909                         VSET(norm,0.0,1.0,0.0);
00910                         state = ASM_EMPTY;
00911                 } else {
00912                         VSUBUNIT(dir,p3,p2);
00913                         VSET(norm, 0.0, 1.0, 0.0);
00914                         state = ASM_FULL;
00915                 }
00916                 break;
00917         case ASM_FULL:
00918                 if (end) {
00919                         VSUBUNIT(dir,p2,p1);
00920                         state = ASM_EMPTY;
00921                 } else {
00922                         VSUBUNIT(dir,p3,p1);
00923                         state = ASM_FULL;
00924                 }
00925         }
00926 
00927         /* go for it */
00928         anim_dirn2mat(mat,dir,norm); /* create basic rotation matrix */
00929         VSET(norm, mat[1], mat[5], 0.0); /* save for next time */
00930         VMOVE(point,p2); /* for main's purposes, the current point is p2 */
00931         return(1); /* return signal go ahead and print */
00932 
00933 }
00934 
00935 
00936 /***************************************
00937  * Other animation routines
00938  ***************************************/
00939 
00940 
00941 /* ANIM_ADD_TRANS 
00942  * @brief
00943  *  Add pre- and post- translation to a rotation matrix.
00944  * The resulting matrix has the effect of performing the first
00945  * translation, followed by the rotation, followed by the second translation.
00946  */
00947 void anim_add_trans(mat_t m, const vect_t post, const vect_t pre)
00948 {
00949         int i;
00950         for (i=0; i<3; i++)
00951         m[3+i*4] += m[i*4]*pre[0] + m[1+i*4]*pre[1]+m[2+i*4]*pre[2] + post[i];
00952 
00953 }
00954 
00955 /* ANIM_ROTATEZ 
00956  * @brief
00957  *  Rotate the vector "d" through "a" radians about the z-axis.
00958  */
00959 void anim_rotatez(fastf_t a, vect_t d)
00960 {
00961         fastf_t temp[3];
00962         fastf_t cos_y = cos(a);
00963         fastf_t sin_y = sin(a);
00964         temp[0] = d[0]*cos_y - d[1]*sin_y;
00965         temp[1] = d[0]*sin_y + d[1]*cos_y;
00966         d[0]=temp[0];
00967         d[1]=temp[1];
00968 }
00969 
00970 /* ANIM_MAT_PRINT 
00971  * @brief
00972  *  print out 4X4 matrix, with optional colon
00973  */
00974 void anim_mat_print(FILE *fp, const mat_t m, int s_colon)
00975 {
00976         bu_flog( fp,"%.10g %.10g %.10g %.10g\n", m[0], m[1], m[2], m[3]);
00977         bu_flog( fp,"%.10g %.10g %.10g %.10g\n", m[4], m[5], m[6], m[7]);
00978         bu_flog( fp,"%.10g %.10g %.10g %.10g\n", m[8], m[9], m[10], m[11]);
00979         bu_flog( fp,"%.10g %.10g %.10g %.10g", m[12], m[13], m[14], m[15]);
00980         if (s_colon)
00981                 bu_flog( fp,";");
00982         bu_flog( fp,"\n");
00983 }
00984 
00985 
00986 
00987 /* ANIM_MAT_PRINTF 
00988  * @brief
00989  *  print out 4X4 matrix
00990  * formstr must be less than twenty chars
00991  */
00992 void anim_mat_printf(
00993         FILE *fp,
00994         const mat_t m,
00995         const char *formstr,
00996         const char *linestr,
00997         const char *endstr)
00998 {
00999         char mystr[80];
01000         sprintf(mystr,"%s%s%s%s%%s",formstr,formstr,formstr,formstr);
01001         bu_flog( fp,mystr, m[0], m[1], m[2], m[3], linestr);
01002         bu_flog( fp,mystr, m[4], m[5], m[6], m[7], linestr);
01003         bu_flog( fp,mystr, m[8], m[9], m[10], m[11], linestr);
01004         bu_flog( fp,mystr, m[12], m[13], m[14], m[15], endstr);
01005 }
01006 
01007 /* ANIM_VIEW_REV 
01008  * @brief
01009  *  Reverse the direction of a view matrix, keeping it
01010  * right-side up
01011  */
01012 void anim_view_rev(mat_t m)
01013 {
01014         m[0] = -m[0];
01015         m[1] = -m[1];
01016         m[4] = -m[4];
01017         m[5] = -m[5];
01018         m[8] = -m[8];
01019         m[9] = -m[9];
01020 }
01021 /*@}*/
01022 /*
01023  * Local Variables:
01024  * mode: C
01025  * tab-width: 8
01026  * c-basic-offset: 4
01027  * indent-tabs-mode: t
01028  * End:
01029  * ex: shiftwidth=4 tabstop=8
01030  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6