mat.c

Go to the documentation of this file.
00001 /*                           M A T . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1996-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 
00022 /** @addtogroup mat */
00023 /*@{*/
00024 
00025 /** @file mat.c
00026  * @brief
00027  * 4 x 4 Matrix manipulation functions...
00028  *
00029  * @li bn_atan2()                       Wrapper for library atan2()
00030  * @li (deprecated) bn_mat_zero( &m )           Fill matrix m with zeros
00031  * @li (deprecated) bn_mat_idn( &m )            Fill matrix m with identity matrix
00032  * @li (deprecated) bn_mat_copy( &o, &i )               Copy matrix i to matrix o
00033  * @li bn_mat_mul( &o, &i1, &i2 )       Multiply i1 by i2 and store in o
00034  * @li bn_mat_mul2( &i, &o )
00035  * @li bn_matXvec( &ov, &m, &iv )       Multiply m by vector iv, store in ov
00036  * @li bn_mat_inv( &om, &im )           Invert matrix im, store result in om
00037  * @li bn_mat_print( &title, &m )       Print matrix (with title) on stderr.
00038  * @li bn_mat_trn( &o, &i )             Transpose matrix i into matrix o
00039  * @li bn_mat_ae( &o, azimuth, elev)    Make rot matrix from azimuth+elevation
00040  * @li bn_ae_vec( &az, &el, v ) Find az/elev from dir vector
00041  * @li bn_aet_vec( &az, &el, &twist, v1, v2 ) Find az,el,twist from two vectors
00042  * @li bn_mat_angles( &o, alpha, beta, gama )   Make rot matrix from angles
00043  * @li bn_eigen2x2()                    Eigen values and vectors
00044  * @li bn_mat_lookat                    Make rot mat:  xform from D to -Z
00045  * @li bn_mat_fromto                    Make rot mat:  xform from A to
00046  * @li bn_mat_arb_rot( &m, pt, dir, ang)        Make rot mat about axis (pt,dir), through ang
00047  * @li bn_mat_is_equal()                Is mat a equal to mat b?
00048  *
00049  *
00050  * Matrix array elements have the following positions in the matrix:
00051 @code
00052                                 |  0  1  2  3 |         | 0 |
00053           [ 0 1 2 3 ]           |  4  5  6  7 |         | 1 |
00054                                 |  8  9 10 11 |         | 2 |
00055                                 | 12 13 14 15 |         | 3 |
00056 @endcode
00057  *
00058  *     preVector (vect_t)        Matrix (mat_t)    postVector (vect_t)
00059  *
00060  *
00061  * @author      Robert S. Miles
00062  * @author      Michael John Muuss
00063  * @author      Lee A. Butler
00064  *
00065  * @par Source
00066  *      The U. S. Army Research Laboratory
00067  *@n    Aberdeen Proving Ground, Maryland  21005-5068  USA
00068  */
00069 
00070 /*@}*/
00071 
00072 #ifndef lint
00073 static const char bn_RCSmat[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/mat.c,v 14.13 2006/09/02 14:02:15 lbutler Exp $ (ARL)";
00074 #endif
00075 
00076 #include "common.h"
00077 
00078 
00079 
00080 #include <stdio.h>
00081 #include <math.h>
00082 
00083 #ifdef HAVE_STRING_H
00084 #include <string.h>
00085 #else
00086 #include <strings.h>
00087 #endif
00088 
00089 #include "machine.h"
00090 #include "bu.h"
00091 #include "vmath.h"
00092 #include "bn.h"
00093 
00094 const mat_t     bn_mat_identity = {
00095                 1.0, 0.0, 0.0, 0.0,
00096                 0.0, 1.0, 0.0, 0.0,
00097                 0.0, 0.0, 1.0, 0.0,
00098                 0.0, 0.0, 0.0, 1.0
00099 };
00100 
00101 /**
00102  *
00103  */
00104 void
00105 bn_mat_print_guts(const char    *title,
00106                   const mat_t   m,
00107                   char          *obuf)
00108 {
00109         register int    i;
00110         register char   *cp;
00111 
00112         sprintf(obuf, "MATRIX %s:\n  ", title);
00113         cp = obuf+strlen(obuf);
00114         if (!m) {
00115                 strcat(obuf, "(Identity)");
00116         } else {
00117                 for (i=0; i<16; i++)  {
00118                         sprintf(cp, " %8.3f", m[i]);
00119                         cp += strlen(cp);
00120                         if (i == 15) {
00121                                 break;
00122                         } else if((i&3) == 3) {
00123                                 *cp++ = '\n';
00124                                 *cp++ = ' ';
00125                                 *cp++ = ' ';
00126                         }
00127                 }
00128                 *cp++ = '\0';
00129         }
00130 }
00131 
00132 /**
00133  *                      B N _ M A T _ P R I N T
00134  */
00135 void
00136 bn_mat_print(const char         *title,
00137              const mat_t        m)
00138 {
00139         char            obuf[1024];     /* sprintf may be non-PARALLEL */
00140 
00141         bn_mat_print_guts(title, m, obuf);
00142         bu_log("%s\n", obuf);
00143 }
00144 
00145 /**
00146  *                      B N _ A T A N 2
00147  * @brief
00148  *  A wrapper for the system atan2().  On the Silicon Graphics,
00149  *  and perhaps on others, x==0 incorrectly returns infinity.
00150  */
00151 double
00152 bn_atan2(double y, double x)
00153 {
00154         if( x > -1.0e-20 && x < 1.0e-20 )  {
00155                 /* X is equal to zero, check Y */
00156                 if( y < -1.0e-20 )  return( -3.14159265358979323/2 );
00157                 if( y >  1.0e-20 )  return(  3.14159265358979323/2 );
00158                 return(0.0);
00159         }
00160         return( atan2( y, x ) );
00161 }
00162 
00163 #if 0  /********* Deprecated for macros that call memcpy() *********/
00164 
00165 /**
00166  *                      B N _ M A T _ Z E R O
00167  *
00168  * Fill in the matrix "m" with zeros.
00169  */
00170 void
00171 bn_mat_zero( m )
00172 mat_t   m;
00173 {
00174         register int i = 0;
00175         register matp_t mp = m;
00176 
00177         bu_log("libbn/mat.c:  bn_mat_zero() is deprecated, use MAT_ZERO()\n");
00178         /* Clear everything */
00179         for(; i<16; i++)
00180                 *mp++ = 0.0;
00181 }
00182 
00183 
00184 
00185 /*
00186  *                      B N _ M A T _ I D N
00187  *
00188  * Fill in the matrix "m" with an identity matrix.
00189  */
00190 void
00191 bn_mat_idn( m )
00192 register mat_t  m;
00193 {
00194         bu_log("libbn/mat.c:  bn_mat_idn() is deprecated, use MAT_IDN()\n");
00195         memcpy(m, bn_mat_identity, sizeof(m));
00196 }
00197 
00198 /*
00199  *                      B N _ M A T _ C O P Y
00200  * Copy the matrix
00201  */
00202 void
00203 bn_mat_copy( dest, src )
00204 register mat_t          dest;
00205 register const mat_t    src;
00206 {
00207         register int i;
00208 
00209         /* Copy all elements */
00210 #       include "noalias.h"
00211         bu_log("libbn/mat.c:  bn_mat_copy() is deprecated, use MAT_COPY()\n");
00212         for( i=15; i>=0; i--)
00213                 dest[i] = src[i];
00214 }
00215 
00216 #endif  /******************* deprecated *******************/
00217 
00218 /**
00219  *                      B N _ M A T _ M U L
00220  *@brief
00221  * Multiply matrix "a" by "b" and store the result in "o".
00222  * NOTE:  This is different from multiplying "b" by "a"
00223  * (most of the time!)
00224  * NOTE: "o" must not be the same as either of the inputs.
00225  */
00226 void
00227 bn_mat_mul(register mat_t o, register const mat_t a, register const mat_t b)
00228 {
00229         o[ 0] = a[ 0]*b[ 0] + a[ 1]*b[ 4] + a[ 2]*b[ 8] + a[ 3]*b[12];
00230         o[ 1] = a[ 0]*b[ 1] + a[ 1]*b[ 5] + a[ 2]*b[ 9] + a[ 3]*b[13];
00231         o[ 2] = a[ 0]*b[ 2] + a[ 1]*b[ 6] + a[ 2]*b[10] + a[ 3]*b[14];
00232         o[ 3] = a[ 0]*b[ 3] + a[ 1]*b[ 7] + a[ 2]*b[11] + a[ 3]*b[15];
00233 
00234         o[ 4] = a[ 4]*b[ 0] + a[ 5]*b[ 4] + a[ 6]*b[ 8] + a[ 7]*b[12];
00235         o[ 5] = a[ 4]*b[ 1] + a[ 5]*b[ 5] + a[ 6]*b[ 9] + a[ 7]*b[13];
00236         o[ 6] = a[ 4]*b[ 2] + a[ 5]*b[ 6] + a[ 6]*b[10] + a[ 7]*b[14];
00237         o[ 7] = a[ 4]*b[ 3] + a[ 5]*b[ 7] + a[ 6]*b[11] + a[ 7]*b[15];
00238 
00239         o[ 8] = a[ 8]*b[ 0] + a[ 9]*b[ 4] + a[10]*b[ 8] + a[11]*b[12];
00240         o[ 9] = a[ 8]*b[ 1] + a[ 9]*b[ 5] + a[10]*b[ 9] + a[11]*b[13];
00241         o[10] = a[ 8]*b[ 2] + a[ 9]*b[ 6] + a[10]*b[10] + a[11]*b[14];
00242         o[11] = a[ 8]*b[ 3] + a[ 9]*b[ 7] + a[10]*b[11] + a[11]*b[15];
00243 
00244         o[12] = a[12]*b[ 0] + a[13]*b[ 4] + a[14]*b[ 8] + a[15]*b[12];
00245         o[13] = a[12]*b[ 1] + a[13]*b[ 5] + a[14]*b[ 9] + a[15]*b[13];
00246         o[14] = a[12]*b[ 2] + a[13]*b[ 6] + a[14]*b[10] + a[15]*b[14];
00247         o[15] = a[12]*b[ 3] + a[13]*b[ 7] + a[14]*b[11] + a[15]*b[15];
00248 }
00249 
00250 /**
00251  *                      B N _ M A T _ M U L 2
00252  *
00253  *  o = i * o
00254  *
00255  *@brief
00256  *  A convenience wrapper for bn_mat_mul() to update a matrix in place.
00257  *  The arugment ordering is confusing either way.
00258  */
00259 void
00260 bn_mat_mul2(register const mat_t i, register mat_t o)
00261 {
00262         mat_t   temp;
00263 
00264         bn_mat_mul( temp, i, o );
00265         MAT_COPY( o, temp );
00266 }
00267 
00268 /**
00269  *                      B N _ M A T _ M U L 3
00270  *
00271  *  o = a * b * c
00272  *
00273  *  The output matrix may be the same as 'b' or 'c', but may not be 'a'.
00274  */
00275 void
00276 bn_mat_mul3(mat_t o, const mat_t a, const mat_t b, const mat_t c)
00277 {
00278         mat_t   t;
00279 
00280         bn_mat_mul( t, b, c );
00281         bn_mat_mul( o, a, t );
00282 }
00283 
00284 /**
00285  *                      B N _ M A T _ M U L 4
00286  *
00287  *  o = a * b * c * d
00288  *
00289  *  The output matrix may be the same as any input matrix.
00290  */
00291 void
00292 bn_mat_mul4(mat_t ao, const mat_t a, const mat_t b, const mat_t c, const mat_t d)
00293 {
00294         mat_t   t, u;
00295 
00296         bn_mat_mul( u, c, d );
00297         bn_mat_mul( t, a, b );
00298         bn_mat_mul( ao, t, u );
00299 }
00300 
00301 /**
00302  *                      B N _ M A T X V E C
00303  *@brief
00304  * Multiply the matrix "im" by the vector "iv" and store the result
00305  * in the vector "ov".  Note this is post-multiply, and
00306  * operates on 4-tuples.  Use MAT4X3VEC() to operate on 3-tuples.
00307  */
00308 void
00309 bn_matXvec(register vect_t ov, register const mat_t im, register const vect_t iv)
00310 {
00311         register int eo = 0;            /* Position in output vector */
00312         register int em = 0;            /* Position in input matrix */
00313         register int ei;                /* Position in input vector */
00314 
00315         /* For each element in the output array... */
00316         for(; eo<4; eo++) {
00317 
00318                 ov[eo] = 0;             /* Start with zero in output */
00319 
00320                 for(ei=0; ei<4; ei++)
00321                         ov[eo] += im[em++] * iv[ei];
00322         }
00323 }
00324 
00325 
00326 /**
00327  *                      B N _ M A T _ I N V
00328  *
00329  * The matrix pointed at by "input" is inverted and stored in the area
00330  * pointed at by "output".
00331  *
00332  * Calls bu_bomb if matrix is singular.
00333  */
00334 void
00335 bn_mat_inv(register mat_t output, const mat_t input)
00336 {
00337         if(bn_mat_inverse(output, input) == 0)  {
00338                 bu_log("bn_mat_inv:  error!");
00339                 bn_mat_print("singular matrix", input);
00340                 bu_bomb("bn_mat_inv: singular matrix\n");
00341                 /* NOTREACHED */
00342         }
00343 }
00344 
00345 
00346 /**
00347  *                      B N _ M A T _ I N V E R S E
00348  *
00349  * The matrix pointed at by "input" is inverted and stored in the area
00350  * pointed at by "output".
00351  *
00352  * Invert a 4-by-4 matrix using Algorithm 120 from ACM.
00353  * This is a modified Gauss-Jordan alogorithm
00354  * Note:  Inversion is done in place, with 3 work vectors
00355  *
00356  *
00357  *  @return      1      if OK.
00358  *  @return      0      if matrix is singular.
00359  */
00360 int
00361 bn_mat_inverse(register mat_t output, const mat_t input)
00362 {
00363         register int i, j;                      /* Indices */
00364         LOCAL int k;                            /* Indices */
00365         LOCAL int       z[4];                   /* Temporary */
00366         LOCAL fastf_t   b[4];                   /* Temporary */
00367         LOCAL fastf_t   c[4];                   /* Temporary */
00368 
00369         MAT_COPY( output, input );      /* Duplicate */
00370 
00371         /* Initialization */
00372         for( j = 0; j < 4; j++ )
00373                 z[j] = j;
00374 
00375         /* Main Loop */
00376         for( i = 0; i < 4; i++ )  {
00377                 FAST fastf_t y;                         /* local temporary */
00378 
00379                 k = i;
00380                 y = output[i*4+i];
00381                 for( j = i+1; j < 4; j++ )  {
00382                         FAST fastf_t w;                 /* local temporary */
00383 
00384                         w = output[i*4+j];
00385                         if( fabs(w) > fabs(y) )  {
00386                                 k = j;
00387                                 y = w;
00388                         }
00389                 }
00390 
00391                 if( fabs(y) < SQRT_SMALL_FASTF )  {
00392                         return 0;
00393                         /* NOTREACHED */
00394                 }
00395                 y = 1.0 / y;
00396 
00397                 for( j = 0; j < 4; j++ )  {
00398                         FAST fastf_t temp;              /* Local */
00399 
00400                         c[j] = output[j*4+k];
00401                         output[j*4+k] = output[j*4+i];
00402                         output[j*4+i] = - c[j] * y;
00403                         temp = output[i*4+j] * y;
00404                         b[j] = temp;
00405                         output[i*4+j] = temp;
00406                 }
00407 
00408                 output[i*4+i] = y;
00409                 j = z[i];
00410                 z[i] = z[k];
00411                 z[k] = j;
00412                 for( k = 0; k < 4; k++ )  {
00413                         if( k == i )  continue;
00414                         for( j = 0; j < 4; j++ )  {
00415                                 if( j == i )  continue;
00416                                 output[k*4+j] = output[k*4+j] - b[j] * c[k];
00417                         }
00418                 }
00419         }
00420 
00421         /*  Second Loop */
00422         for( i = 0; i < 4; i++ )  {
00423                 while( (k = z[i]) != i )  {
00424                         LOCAL int p;                    /* Local temp */
00425 
00426                         for( j = 0; j < 4; j++ )  {
00427                                 FAST fastf_t w;         /* Local temp */
00428 
00429                                 w = output[i*4+j];
00430                                 output[i*4+j] = output[k*4+j];
00431                                 output[k*4+j] = w;
00432                         }
00433                         p = z[i];
00434                         z[i] = z[k];
00435                         z[k] = p;
00436                 }
00437         }
00438 
00439         return 1;
00440 }
00441 
00442 /*
00443  *                      B N _ V T O H _ M O V E
00444  *
00445  * Takes a pointer to a [x,y,z] vector, and a pointer
00446  * to space for a homogeneous vector [x,y,z,w],
00447  * and builds [x,y,z,1].
00448 void
00449 bn_vtoh_move(register vert_t h2, register const vert_t v2)
00450 {
00451         h2[X] = v2[X];
00452         h2[Y] = v2[Y];
00453         h2[Z] = v2[Z];
00454         h2[W] = 1.0;
00455 }
00456  */
00457 
00458 /**
00459  *                      B N _ H T O V _ M O V E
00460  *
00461  * Takes a pointer to [x,y,z,w], and converts it to
00462  * an ordinary vector [x/w, y/w, z/w].
00463  * Optimization for the case of w==1 is performed.
00464  */
00465 void
00466 bn_htov_move(register vect_t v, register const vect_t h)
00467 {
00468         register fastf_t inv;
00469 
00470         if( h[3] == 1.0 )  {
00471                 v[X] = h[X];
00472                 v[Y] = h[Y];
00473                 v[Z] = h[Z];
00474         }  else  {
00475                 if( h[W] == SMALL_FASTF )  {
00476                         bu_log("bn_htov_move: divide by %f!\n", h[W]);
00477                         return;
00478                 }
00479                 inv = 1.0 / h[W];
00480                 v[X] = h[X] * inv;
00481                 v[Y] = h[Y] * inv;
00482                 v[Z] = h[Z] * inv;
00483         }
00484 }
00485 
00486 
00487 /**
00488  *                      B N _ M A T _ T R N
00489  */
00490 void
00491 bn_mat_trn(mat_t om, register const mat_t im)
00492 {
00493         register matp_t op = om;
00494 
00495         *op++ = im[0];
00496         *op++ = im[4];
00497         *op++ = im[8];
00498         *op++ = im[12];
00499 
00500         *op++ = im[1];
00501         *op++ = im[5];
00502         *op++ = im[9];
00503         *op++ = im[13];
00504 
00505         *op++ = im[2];
00506         *op++ = im[6];
00507         *op++ = im[10];
00508         *op++ = im[14];
00509 
00510         *op++ = im[3];
00511         *op++ = im[7];
00512         *op++ = im[11];
00513         *op++ = im[15];
00514 }
00515 
00516 /**
00517  *                      B N _ M A T _ A E
00518  *
00519  *  Compute a 4x4 rotation matrix given Azimuth and Elevation.
00520  *
00521  *  Azimuth is +X, Elevation is +Z, both in degrees.
00522  *
00523  *  Formula due to Doug Gwyn, BRL.
00524  */
00525 void
00526 bn_mat_ae(register fastf_t *m, double azimuth, double elev)
00527 {
00528         LOCAL double sin_az, sin_el;
00529         LOCAL double cos_az, cos_el;
00530 
00531         azimuth *= bn_degtorad;
00532         elev *= bn_degtorad;
00533 
00534         sin_az = sin(azimuth);
00535         cos_az = cos(azimuth);
00536         sin_el = sin(elev);
00537         cos_el = cos(elev);
00538 
00539         m[0] = cos_el * cos_az;
00540         m[1] = -sin_az;
00541         m[2] = -sin_el * cos_az;
00542         m[3] = 0;
00543 
00544         m[4] = cos_el * sin_az;
00545         m[5] = cos_az;
00546         m[6] = -sin_el * sin_az;
00547         m[7] = 0;
00548 
00549         m[8] = sin_el;
00550         m[9] = 0;
00551         m[10] = cos_el;
00552         m[11] = 0;
00553 
00554         m[12] = m[13] = m[14] = 0;
00555         m[15] = 1.0;
00556 }
00557 
00558 /**
00559  *                      B N _ A E _ V E C
00560  *
00561  *  Find the azimuth and elevation angles that correspond to the
00562  *  direction (not including twist) given by a direction vector.
00563  */
00564 void
00565 bn_ae_vec(fastf_t *azp, fastf_t *elp, const vect_t v)
00566 {
00567         register fastf_t        az;
00568 
00569         if( (az = bn_atan2( v[Y], v[X] ) * bn_radtodeg) < 0 )  {
00570                 *azp = 360 + az;
00571         } else if( az >= 360 ) {
00572                 *azp = az - 360;
00573         } else {
00574                 *azp = az;
00575         }
00576         *elp = bn_atan2( v[Z], hypot( v[X], v[Y] ) ) * bn_radtodeg;
00577 }
00578 
00579 /**                     B N _ A E T _ V E C
00580  *@brief
00581  * Find the azimuth, elevation, and twist from two vectors.
00582  * Vec_ae is in the direction of view (+z in mged view)
00583  * and vec_twist points to the viewers right (+x in mged view).
00584  * Accuracy (degrees) is used to stabilze flutter between
00585  * equivalent extremes of atan2(), and to snap twist to zero
00586  * when elevation is near +/- 90
00587  */
00588 void
00589 bn_aet_vec(fastf_t *az, fastf_t *el, fastf_t *twist, fastf_t *vec_ae, fastf_t *vec_twist, fastf_t accuracy)
00590 {
00591         vect_t zero_twist,ninety_twist;
00592         vect_t z_dir;
00593 
00594         /* Get az and el as usual */
00595         bn_ae_vec( az , el , vec_ae );
00596 
00597         /* stabilize fluctuation bewteen 0 and 360
00598          * change azimuth near 360 to 0 */
00599         if( NEAR_ZERO( *az - 360.0 , accuracy ) )
00600                 *az = 0.0;
00601 
00602         /* if elevation is +/-90 set twist to zero and calculate azimuth */
00603         if( NEAR_ZERO( *el - 90.0 , accuracy ) || NEAR_ZERO( *el + 90.0 , accuracy ) )
00604         {
00605                 *twist = 0.0;
00606                 *az = bn_atan2( -vec_twist[X] , vec_twist[Y] ) * bn_radtodeg;
00607         }
00608         else
00609         {
00610                 /* Calculate twist from vec_twist */
00611                 VSET( z_dir , 0 , 0 , 1 );
00612                 VCROSS( zero_twist , z_dir , vec_ae );
00613                 VUNITIZE( zero_twist );
00614                 VCROSS( ninety_twist , vec_ae , zero_twist );
00615                 VUNITIZE( ninety_twist );
00616 
00617                 *twist = bn_atan2( VDOT( vec_twist , ninety_twist ) , VDOT( vec_twist , zero_twist ) ) * bn_radtodeg;
00618 
00619                 /* stabilize flutter between +/- 180 */
00620                 if( NEAR_ZERO( *twist + 180.0 , accuracy ) )
00621                         *twist = 180.0;
00622         }
00623 }
00624 
00625 
00626 /**
00627  *                      B N _ M A T _ A N G L E S
00628  *
00629  * This routine builds a Homogeneous rotation matrix, given
00630  * alpha, beta, and gamma as angles of rotation, in degrees.
00631  *
00632  * Alpha is angle of rotation about the X axis, and is done third.
00633  * Beta is angle of rotation about the Y axis, and is done second.
00634  * Gamma is angle of rotation about Z axis, and is done first.
00635  */
00636 void
00637 bn_mat_angles(register fastf_t *mat, double alpha_in, double beta_in, double ggamma_in)
00638 {
00639         LOCAL double alpha, beta, ggamma;
00640         LOCAL double calpha, cbeta, cgamma;
00641         LOCAL double salpha, sbeta, sgamma;
00642 
00643         if( alpha_in == 0.0 && beta_in == 0.0 && ggamma_in == 0.0 )  {
00644                 MAT_IDN( mat );
00645                 return;
00646         }
00647 
00648         alpha = alpha_in * bn_degtorad;
00649         beta = beta_in * bn_degtorad;
00650         ggamma = ggamma_in * bn_degtorad;
00651 
00652         calpha = cos( alpha );
00653         cbeta = cos( beta );
00654         cgamma = cos( ggamma );
00655 
00656         /* sine of "180*bn_degtorad" will not be exactly zero
00657          * and will result in errors when some codes try to
00658          * convert this back to azimuth and elevation.
00659          * do_frame() uses this technique!!!
00660          */
00661         if( alpha_in == 180.0 )
00662                 salpha = 0.0;
00663         else
00664                 salpha = sin( alpha );
00665 
00666         if( beta_in == 180.0 )
00667                 sbeta = 0.0;
00668         else
00669                 sbeta = sin( beta );
00670 
00671         if( ggamma_in == 180.0 )
00672                 sgamma = 0.0;
00673         else
00674                 sgamma = sin( ggamma );
00675 
00676         mat[0] = cbeta * cgamma;
00677         mat[1] = -cbeta * sgamma;
00678         mat[2] = sbeta;
00679         mat[3] = 0.0;
00680 
00681         mat[4] = salpha * sbeta * cgamma + calpha * sgamma;
00682         mat[5] = -salpha * sbeta * sgamma + calpha * cgamma;
00683         mat[6] = -salpha * cbeta;
00684         mat[7] = 0.0;
00685 
00686         mat[8] = salpha * sgamma - calpha * sbeta * cgamma;
00687         mat[9] = salpha * cgamma + calpha * sbeta * sgamma;
00688         mat[10] = calpha * cbeta;
00689         mat[11] = 0.0;
00690         mat[12] = mat[13] = mat[14] = 0.0;
00691         mat[15] = 1.0;
00692 }
00693 
00694 /**
00695  *                      B N _ M A T _ A N G L E S _ R A D
00696  *@brief
00697  * This routine builds a Homogeneous rotation matrix, given
00698  * alpha, beta, and gamma as angles of rotation, in radians.
00699  *
00700  * Alpha is angle of rotation about the X axis, and is done third.
00701  * Beta is angle of rotation about the Y axis, and is done second.
00702  * Gamma is angle of rotation about Z axis, and is done first.
00703  */
00704 void
00705 bn_mat_angles_rad(register mat_t        mat,
00706                   double                alpha,
00707                   double                beta,
00708                   double                ggamma)
00709 {
00710         LOCAL double calpha, cbeta, cgamma;
00711         LOCAL double salpha, sbeta, sgamma;
00712 
00713         if (alpha == 0.0 && beta == 0.0 && ggamma == 0.0) {
00714                 MAT_IDN( mat );
00715                 return;
00716         }
00717 
00718         calpha = cos( alpha );
00719         cbeta = cos( beta );
00720         cgamma = cos( ggamma );
00721 
00722         salpha = sin( alpha );
00723         sbeta = sin( beta );
00724         sgamma = sin( ggamma );
00725 
00726         mat[0] = cbeta * cgamma;
00727         mat[1] = -cbeta * sgamma;
00728         mat[2] = sbeta;
00729         mat[3] = 0.0;
00730 
00731         mat[4] = salpha * sbeta * cgamma + calpha * sgamma;
00732         mat[5] = -salpha * sbeta * sgamma + calpha * cgamma;
00733         mat[6] = -salpha * cbeta;
00734         mat[7] = 0.0;
00735 
00736         mat[8] = salpha * sgamma - calpha * sbeta * cgamma;
00737         mat[9] = salpha * cgamma + calpha * sbeta * sgamma;
00738         mat[10] = calpha * cbeta;
00739         mat[11] = 0.0;
00740         mat[12] = mat[13] = mat[14] = 0.0;
00741         mat[15] = 1.0;
00742 }
00743 
00744 /**
00745  *                      B N _ E I G E N 2 X 2
00746  *
00747  *  Find the eigenvalues and eigenvectors of a
00748  *  symmetric 2x2 matrix.
00749  *      ( a b )
00750  *      ( b c )
00751  *
00752  *  The eigenvalue with the smallest absolute value is
00753  *  returned in val1, with its eigenvector in vec1.
00754  */
00755 void
00756 bn_eigen2x2(fastf_t *val1, fastf_t *val2, fastf_t *vec1, fastf_t *vec2, fastf_t a, fastf_t b, fastf_t c)
00757 {
00758         fastf_t d, root;
00759         fastf_t v1, v2;
00760 
00761         d = 0.5 * (c - a);
00762 
00763         /* Check for diagonal matrix */
00764         if( NEAR_ZERO(b, 1.0e-10) ) {
00765                 /* smaller mag first */
00766                 if( fabs(c) < fabs(a) ) {
00767                         *val1 = c;
00768                         VSET( vec1, 0.0, 1.0, 0.0 );
00769                         *val2 = a;
00770                         VSET( vec2, -1.0, 0.0, 0.0 );
00771                 } else {
00772                         *val1 = a;
00773                         VSET( vec1, 1.0, 0.0, 0.0 );
00774                         *val2 = c;
00775                         VSET( vec2, 0.0, 1.0, 0.0 );
00776                 }
00777                 return;
00778         }
00779 
00780         root = sqrt( d*d + b*b );
00781         v1 = 0.5 * (c + a) - root;
00782         v2 = 0.5 * (c + a) + root;
00783 
00784         /* smaller mag first */
00785         if( fabs(v1) < fabs(v2) ) {
00786                 *val1 = v1;
00787                 *val2 = v2;
00788                 VSET( vec1, b, d - root, 0.0 );
00789         } else {
00790                 *val1 = v2;
00791                 *val2 = v1;
00792                 VSET( vec1, root - d, b, 0.0 );
00793         }
00794         VUNITIZE( vec1 );
00795         VSET( vec2, -vec1[Y], vec1[X], 0.0 );   /* vec1 X vec2 = +Z */
00796 }
00797 
00798 /**
00799  *                      B N _ V E C _ P E R P
00800  *@brief
00801  *  Given a vector, create another vector which is perpendicular to it.
00802  *  The output vector will have unit length only if the input vector did.
00803  */
00804 void
00805 bn_vec_perp(vect_t new, const vect_t old)
00806 {
00807         register int i;
00808         LOCAL vect_t another;   /* Another vector, different */
00809 
00810         i = X;
00811         if( fabs(old[Y])<fabs(old[i]) )  i=Y;
00812         if( fabs(old[Z])<fabs(old[i]) )  i=Z;
00813         VSETALL( another, 0 );
00814         another[i] = 1.0;
00815         if( old[X] == 0 && old[Y] == 0 && old[Z] == 0 )  {
00816                 VMOVE( new, another );
00817         } else {
00818                 VCROSS( new, another, old );
00819         }
00820 }
00821 
00822 /**
00823  *                      B N _ M A T _ F R O M T O
00824  *@brief
00825  *  Given two vectors, compute a rotation matrix that will transform
00826  *  space by the angle between the two.  There are many
00827  *  candidate matricies.
00828  *
00829  *  The input 'from' and 'to' vectors need not be unit length.
00830  *  MAT4X3VEC( to, m, from ) is the identity that is created.
00831  */
00832 void
00833 bn_mat_fromto(mat_t m, const vect_t from, const vect_t to)
00834 {
00835         vect_t  test_to;
00836         vect_t  unit_from, unit_to;
00837         fastf_t dot;
00838 
00839         /*
00840          *  The method used here is from Graphics Gems, A. Glasner, ed.
00841          *  page 531, "The Use of Coordinate Frames in Computer Graphics",
00842          *  by Ken Turkowski, Example 6.
00843          */
00844         mat_t   Q, Qt;
00845         mat_t   R;
00846         mat_t   A;
00847         mat_t   temp;
00848         vect_t  N, M;
00849         vect_t  w_prime;                /* image of "to" ("w") in Qt */
00850 
00851         VMOVE( unit_from, from );
00852         VUNITIZE( unit_from );          /* aka "v" */
00853         VMOVE( unit_to, to );
00854         VUNITIZE( unit_to );            /* aka "w" */
00855 
00856         /*  If from and to are the same or opposite, special handling
00857          *  is needed, because the cross product isn't defined.
00858          *  asin(0.00001) = 0.0005729 degrees (1/2000 degree)
00859          */
00860         dot = VDOT(unit_from, unit_to);
00861         if( dot > 1.0-0.00001 )  {
00862                 /* dot == 1, return identity matrix */
00863                 MAT_IDN(m);
00864                 return;
00865         }
00866         if( dot < -1.0+0.00001 )  {
00867                 /* dot == -1, select random perpendicular N vector */
00868                 bn_vec_perp( N, unit_from );
00869         } else {
00870                 VCROSS( N, unit_from, unit_to );
00871                 VUNITIZE( N );                  /* should be unnecessary */
00872         }
00873         VCROSS( M, N, unit_from );
00874         VUNITIZE( M );                  /* should be unnecessary */
00875 
00876         /* Almost everything here is done with pre-multiplys:  vector * mat */
00877         MAT_IDN( Q );
00878         VMOVE( &Q[0], unit_from );
00879         VMOVE( &Q[4], M );
00880         VMOVE( &Q[8], N );
00881         bn_mat_trn( Qt, Q );
00882 
00883         /* w_prime = w * Qt */
00884         MAT4X3VEC( w_prime, Q, unit_to );       /* post-multiply by transpose */
00885 
00886         MAT_IDN( R );
00887         VMOVE( &R[0], w_prime );
00888         VSET( &R[4], -w_prime[Y], w_prime[X], w_prime[Z] );
00889         VSET( &R[8], 0, 0, 1 );         /* is unnecessary */
00890 
00891         bn_mat_mul( temp, R, Q );
00892         bn_mat_mul( A, Qt, temp );
00893         bn_mat_trn( m, A );             /* back to post-multiply style */
00894 
00895         /* Verify that it worked */
00896         MAT4X3VEC( test_to, m, unit_from );
00897         dot = VDOT( unit_to, test_to );
00898         if( dot < 0.98 || dot > 1.02 )  {
00899                 bu_log("bn_mat_fromto() ERROR!  from (%g,%g,%g) to (%g,%g,%g) went to (%g,%g,%g), dot=%g?\n",
00900                         V3ARGS(from),
00901                         V3ARGS(to),
00902                         V3ARGS( test_to ), dot );
00903         }
00904 }
00905 
00906 /**
00907  *                      B N _ M A T _ X R O T
00908  *
00909  *  Given the sin and cos of an X rotation angle, produce the rotation matrix.
00910  */
00911 void
00912 bn_mat_xrot(fastf_t *m, double sinx, double cosx)
00913 {
00914         m[0] = 1.0;
00915         m[1] = 0.0;
00916         m[2] = 0.0;
00917         m[3] = 0.0;
00918 
00919         m[4] = 0.0;
00920         m[5] = cosx;
00921         m[6] = -sinx;
00922         m[7] = 0.0;
00923 
00924         m[8] = 0.0;
00925         m[9] = sinx;
00926         m[10] = cosx;
00927         m[11] = 0.0;
00928 
00929         m[12] = m[13] = m[14] = 0.0;
00930         m[15] = 1.0;
00931 }
00932 
00933 /**
00934  *                      B N _ M A T _ Y R O T
00935  *@brief
00936  *  Given the sin and cos of a Y rotation angle, produce the rotation matrix.
00937  */
00938 void
00939 bn_mat_yrot(fastf_t *m, double siny, double cosy)
00940 {
00941         m[0] = cosy;
00942         m[1] = 0.0;
00943         m[2] = -siny;
00944         m[3] = 0.0;
00945 
00946         m[4] = 0.0;
00947         m[5] = 1.0;
00948         m[6] = 0.0;
00949         m[7] = 0.0;
00950 
00951         m[8] = siny;
00952         m[9] = 0.0;
00953         m[10] = cosy;
00954 
00955         m[11] = 0.0;
00956         m[12] = m[13] = m[14] = 0.0;
00957         m[15] = 1.0;
00958 }
00959 
00960 /**
00961  *                      B N _ M A T _ Z R O T
00962  *@brief
00963  *  Given the sin and cos of a Z rotation angle, produce the rotation matrix.
00964  */
00965 void
00966 bn_mat_zrot(fastf_t *m, double sinz, double cosz)
00967 {
00968         m[0] = cosz;
00969         m[1] = -sinz;
00970         m[2] = 0.0;
00971         m[3] = 0.0;
00972 
00973         m[4] = sinz;
00974         m[5] = cosz;
00975         m[6] = 0.0;
00976         m[7] = 0.0;
00977 
00978         m[8] = 0.0;
00979         m[9] = 0.0;
00980         m[10] = 1.0;
00981         m[11] = 0.0;
00982 
00983         m[12] = m[13] = m[14] = 0.0;
00984         m[15] = 1.0;
00985 }
00986 
00987 
00988 /**
00989  *                      B N _ M A T _ L O O K A T
00990  *
00991  *  Given a direction vector D of unit length,
00992  *  product a matrix which rotates that vector D onto the -Z axis.
00993  *  This matrix will be suitable for use as a "model2view" matrix.
00994  *
00995  *  XXX This routine will fail if the vector is already more or less aligned
00996  *  with the Z axis.
00997  *
00998  *  This is done in several steps.
00999 @code
01000         1)  Rotate D about Z to match +X axis.  Azimuth adjustment.
01001         2)  Rotate D about Y to match -Y axis.  Elevation adjustment.
01002         3)  Rotate D about Z to make projection of X axis again point
01003             in the +X direction.  Twist adjustment.
01004         4)  Optionally, flip sign on Y axis if original Z becomes inverted.
01005             This can be nice for static frames, but is astonishing when
01006             used in animation.
01007 @endcode
01008  */
01009 void
01010 bn_mat_lookat(mat_t rot, const vect_t dir, int yflip)
01011 {
01012         mat_t   first;
01013         mat_t   second;
01014         mat_t   prod12;
01015         mat_t   third;
01016         vect_t  x;
01017         vect_t  z;
01018         vect_t  t1;
01019         fastf_t hypot_xy;
01020         vect_t  xproj;
01021         vect_t  zproj;
01022 
01023         /* First, rotate D around Z axis to match +X axis (azimuth) */
01024         hypot_xy = hypot( dir[X], dir[Y] );
01025         bn_mat_zrot( first, -dir[Y] / hypot_xy, dir[X] / hypot_xy );
01026 
01027         /* Next, rotate D around Y axis to match -Z axis (elevation) */
01028         bn_mat_yrot( second, -hypot_xy, -dir[Z] );
01029         bn_mat_mul( prod12, second, first );
01030 
01031         /* Produce twist correction, by re-orienting projection of X axis */
01032         VSET( x, 1, 0, 0 );
01033         MAT4X3VEC( xproj, prod12, x );
01034         hypot_xy = hypot( xproj[X], xproj[Y] );
01035         if( hypot_xy < 1.0e-10 )  {
01036                 bu_log("Warning: bn_mat_lookat:  unable to twist correct, hypot=%g\n", hypot_xy);
01037                 VPRINT( "xproj", xproj );
01038                 MAT_COPY( rot, prod12 );
01039                 return;
01040         }
01041         bn_mat_zrot( third, -xproj[Y] / hypot_xy, xproj[X] / hypot_xy );
01042         bn_mat_mul( rot, third, prod12 );
01043 
01044         if( yflip )  {
01045                 VSET( z, 0, 0, 1 );
01046                 MAT4X3VEC( zproj, rot, z );
01047                 /* If original Z inverts sign, flip sign on resulting Y */
01048                 if( zproj[Y] < 0.0 )  {
01049                         MAT_COPY( prod12, rot );
01050                         MAT_IDN( third );
01051                         third[5] = -1;
01052                         bn_mat_mul( rot, third, prod12 );
01053                 }
01054         }
01055 
01056         /* Check the final results */
01057         MAT4X3VEC( t1, rot, dir );
01058         if( t1[Z] > -0.98 )  {
01059                 bu_log("Error:  bn_mat_lookat final= (%g, %g, %g)\n", t1[X], t1[Y], t1[Z] );
01060         }
01061 }
01062 
01063 /**
01064  *                      B N _ V E C _ O R T H O
01065  *@brief
01066  *  Given a vector, create another vector which is perpendicular to it,
01067  *  and with unit length.  This algorithm taken from Gift's arvec.f;
01068  *  a faster algorithm may be possible.
01069  */
01070 void
01071 bn_vec_ortho(register vect_t out, register const vect_t in)
01072 {
01073         register int j, k;
01074         FAST fastf_t    f;
01075         register int i;
01076 
01077         if( NEAR_ZERO(in[X], 0.0001) && NEAR_ZERO(in[Y], 0.0001) &&
01078             NEAR_ZERO(in[Z], 0.0001) )  {
01079                 VSETALL( out, 0 );
01080                 VPRINT("bn_vec_ortho: zero-length input", in);
01081                 return;
01082         }
01083 
01084         /* Find component closest to zero */
01085         f = fabs(in[X]);
01086         i = X;
01087         j = Y;
01088         k = Z;
01089         if( fabs(in[Y]) < f )  {
01090                 f = fabs(in[Y]);
01091                 i = Y;
01092                 j = Z;
01093                 k = X;
01094         }
01095         if( fabs(in[Z]) < f )  {
01096                 i = Z;
01097                 j = X;
01098                 k = Y;
01099         }
01100         f = hypot( in[j], in[k] );
01101         if( NEAR_ZERO( f, SMALL ) ) {
01102                 VPRINT("bn_vec_ortho: zero hypot on", in);
01103                 VSETALL( out, 0 );
01104                 return;
01105         }
01106         f = 1.0/f;
01107         out[i] = 0.0;
01108         out[j] = -in[k]*f;
01109         out[k] =  in[j]*f;
01110 }
01111 
01112 
01113 /**
01114  *                      B N _ M A T _ S C A L E _ A B O U T _ P T
01115  *@brief
01116  *  Build a matrix to scale uniformly around a given point.
01117  *
01118  *
01119  *  @return     -1      if scale is too small.
01120  *  @return      0      if OK.
01121  */
01122 int
01123 bn_mat_scale_about_pt(mat_t mat, const point_t pt, const double scale)
01124 {
01125         mat_t   xlate;
01126         mat_t   s;
01127         mat_t   tmp;
01128 
01129         MAT_IDN( xlate );
01130         MAT_DELTAS_VEC_NEG( xlate, pt );
01131 
01132         MAT_IDN( s );
01133         if( NEAR_ZERO( scale, SMALL ) )  {
01134                 MAT_ZERO( mat );
01135                 return -1;                      /* ERROR */
01136         }
01137         s[15] = 1/scale;
01138 
01139         bn_mat_mul( tmp, s, xlate );
01140 
01141         MAT_DELTAS_VEC( xlate, pt );
01142         bn_mat_mul( mat, xlate, tmp );
01143         return 0;                               /* OK */
01144 }
01145 
01146 /**
01147  *                      B N _ M A T _ X F O R M _ A B O U T _ P T
01148  *@brief
01149  *  Build a matrix to apply arbitary 4x4 transformation around a given point.
01150  */
01151 void
01152 bn_mat_xform_about_pt(mat_t mat, const mat_t xform, const point_t pt)
01153 {
01154         mat_t   xlate;
01155         mat_t   tmp;
01156 
01157         MAT_IDN( xlate );
01158         MAT_DELTAS_VEC_NEG( xlate, pt );
01159 
01160         bn_mat_mul( tmp, xform, xlate );
01161 
01162         MAT_DELTAS_VEC( xlate, pt );
01163         bn_mat_mul( mat, xlate, tmp );
01164 }
01165 
01166 /**
01167  *                      B N _ M A T _ I S _ E Q U A L
01168  *
01169  *
01170  *  @Return     0       When matrices are not equal
01171  *  @Return     1       When matricies are equal
01172  */
01173 int
01174 bn_mat_is_equal(const mat_t a, const mat_t b, const struct bn_tol *tol)
01175 {
01176         register int i;
01177         register double f;
01178         register double tdist, tperp;
01179 
01180         BN_CK_TOL(tol);
01181 
01182         tdist = tol->dist;
01183         tperp = tol->perp;
01184 
01185         /*
01186          * First, check that the translation part of the matrix (dist) are
01187          * within the distance tolerance.
01188          * Because most instancing involves translation and no rotation,
01189          * doing this first should detect most non-equal cases rapidly.
01190          */
01191         for (i=3; i<12; i+=4) {
01192                 f = a[i] - b[i];
01193                 if ( !NEAR_ZERO(f, tdist)) return 0;
01194         }
01195 
01196         /*
01197          * Check that the rotation part of the matrix (cosines) are within
01198          * the perpendicular tolerance.
01199          */
01200         for (i = 0; i < 16; i+=4) {
01201                 f = a[i] - b[i];
01202                 if ( !NEAR_ZERO(f, tperp)) return 0;
01203                 f = a[i+1] - b[i+1];
01204                 if ( !NEAR_ZERO(f, tperp)) return 0;
01205                 f = a[i+2] - b[i+2];
01206                 if ( !NEAR_ZERO(f, tperp)) return 0;
01207         }
01208         /*
01209          * Check that the scale part of the matrix (ratio) is within the
01210          * perpendicular tolerance.  There is no ratio tolerance so we use
01211          * the tighter of dist or perp.
01212          */
01213         f = a[15] - b[15];
01214         if ( !NEAR_ZERO(f, tperp)) return 0;
01215 
01216         return 1;
01217 }
01218 
01219 
01220 /**
01221  *                      B N _ M A T _ I S _ I D E N T I T Y
01222  *
01223  *  This routine is intended for detecting identity matricies read in
01224  *  from ascii or binary files, where the numbers are pure ones or zeros.
01225  *  This routine is *not* intended for tolerance-based "near-zero"
01226  *  comparisons; as such, it shouldn't be used on matrices which are
01227  *  the result of calculation.
01228  *
01229  *
01230  *  @return     0       non-identity
01231  *  @return     1       a perfect identity matrix
01232  */
01233 int
01234 bn_mat_is_identity(const mat_t m)
01235 {
01236         return (! memcmp(m, bn_mat_identity, sizeof(mat_t)));
01237 }
01238 
01239 /**     B N _ M A T _ A R B _ R O T
01240  *
01241  *@brief
01242  * Construct a transformation matrix for rotation about an arbitrary axis
01243  *
01244  *      The axis is defined by a point (pt) and a unit direction vector (dir).
01245  *      The angle of rotation is "ang"
01246  */
01247 void
01248 bn_mat_arb_rot(mat_t m, const point_t pt, const vect_t dir, const fastf_t ang)
01249 {
01250         mat_t tran1,tran2,rot;
01251         double cos_ang, sin_ang, one_m_cosang;
01252         double n1_sq, n2_sq, n3_sq;
01253         double n1_n2, n1_n3, n2_n3;
01254 
01255         if( ang == 0.0 )
01256         {
01257                 MAT_IDN( m );
01258                 return;
01259         }
01260 
01261         MAT_IDN( tran1 );
01262         MAT_IDN( tran2 );
01263 
01264         /* construct translation matrix to pt */
01265         tran1[MDX] = (-pt[X]);
01266         tran1[MDY] = (-pt[Y]);
01267         tran1[MDZ] = (-pt[Z]);
01268 
01269         /* construct translation back from pt */
01270         tran2[MDX] = pt[X];
01271         tran2[MDY] = pt[Y];
01272         tran2[MDZ] = pt[Z];
01273 
01274         /* construct rotation matrix */
01275         cos_ang = cos( ang );
01276         sin_ang = sin( ang );
01277         one_m_cosang = 1.0 - cos_ang;
01278         n1_sq = dir[X]*dir[X];
01279         n2_sq = dir[Y]*dir[Y];
01280         n3_sq = dir[Z]*dir[Z];
01281         n1_n2 = dir[X]*dir[Y];
01282         n1_n3 = dir[X]*dir[Z];
01283         n2_n3 = dir[Y]*dir[Z];
01284 
01285         MAT_IDN( rot );
01286         rot[0] = n1_sq + (1.0 - n1_sq)*cos_ang;
01287         rot[1] = n1_n2 * one_m_cosang - dir[Z]*sin_ang;
01288         rot[2] = n1_n3 * one_m_cosang + dir[Y]*sin_ang;
01289 
01290         rot[4] = n1_n2 * one_m_cosang + dir[Z]*sin_ang;
01291         rot[5] = n2_sq + (1.0 - n2_sq)*cos_ang;
01292         rot[6] = n2_n3 * one_m_cosang - dir[X]*sin_ang;
01293 
01294         rot[8] = n1_n3 * one_m_cosang - dir[Y]*sin_ang;
01295         rot[9] = n2_n3 * one_m_cosang + dir[X]*sin_ang;
01296         rot[10] = n3_sq + (1.0 - n3_sq) * cos_ang;
01297 
01298         bn_mat_mul( m, rot, tran1 );
01299         bn_mat_mul2( tran2, m );
01300 }
01301 
01302 
01303 /**
01304  *                      B N _ M A T _ D U P
01305  *
01306  *  Return a pointer to a copy of the matrix in dynamically allocated memory.
01307  */
01308 matp_t
01309 bn_mat_dup(const mat_t in)
01310 {
01311         matp_t  out;
01312 
01313         out = (matp_t) bu_malloc( sizeof(mat_t), "bn_mat_dup" );
01314         bcopy( (const char *)in, (char *)out, sizeof(mat_t) );
01315         return out;
01316 }
01317 
01318 /**
01319  *                      B N _ M A T _ C K
01320  *
01321  *  Check to ensure that a rotation matrix preserves axis perpendicularily.
01322  *  Note that not all matricies are rotation matricies.
01323  *
01324  *
01325  *  @return     -1      FAIL
01326  *  @return      0      OK
01327  */
01328 int
01329 bn_mat_ck(const char *title, const mat_t m)
01330 {
01331         vect_t  A, B, C;
01332         fastf_t fx, fy, fz;
01333 
01334         if( !m )  return 0;             /* implies identity matrix */
01335 
01336         /*
01337          * Validate that matrix preserves perpendicularity of axis
01338          * by checking that A.B == 0, B.C == 0, A.C == 0
01339          * XXX these vectors should just be grabbed out of the matrix
01340          */
01341 #if 0
01342         MAT4X3VEC( A, m, xaxis );
01343         MAT4X3VEC( B, m, yaxis );
01344         MAT4X3VEC( C, m, zaxis );
01345 #else
01346         VMOVE( A, &m[0] );
01347         VMOVE( B, &m[4] );
01348         VMOVE( C, &m[8] );
01349 #endif
01350         fx = VDOT( A, B );
01351         fy = VDOT( B, C );
01352         fz = VDOT( A, C );
01353         if( ! NEAR_ZERO(fx, 0.0001) ||
01354             ! NEAR_ZERO(fy, 0.0001) ||
01355             ! NEAR_ZERO(fz, 0.0001) ||
01356             NEAR_ZERO( m[15], VDIVIDE_TOL )
01357         )  {
01358                 bu_log("bn_mat_ck(%s):  bad matrix, does not preserve axis perpendicularity.\n  X.Y=%g, Y.Z=%g, X.Z=%g, s=%g\n",
01359                         title, fx, fy, fz, m[15] );
01360                 bn_mat_print("bn_mat_ck() bad matrix", m);
01361 
01362                 if( bu_debug & (BU_DEBUG_MATH | BU_DEBUG_COREDUMP) )  {
01363                         bu_debug |= BU_DEBUG_COREDUMP;
01364                         bu_bomb("bn_mat_ck() bad matrix\n");
01365                 }
01366                 return -1;      /* FAIL */
01367         }
01368         return 0;               /* OK */
01369 }
01370 
01371 /**
01372  *              B N _ M A T _ D E T 3
01373  *
01374  *      Calculates the determinant of the 3X3 "rotation"
01375  *      part of the passed matrix
01376  */
01377 fastf_t
01378 bn_mat_det3(const mat_t m)
01379 {
01380         FAST fastf_t sum;
01381 
01382         sum = m[0] * ( m[5]*m[10] - m[6]*m[9] )
01383              -m[1] * ( m[4]*m[10] - m[6]*m[8] )
01384              +m[2] * ( m[4]*m[9] - m[5]*m[8] );
01385 
01386         return( sum );
01387 }
01388 
01389 
01390 /**
01391  *              B N _ M A T _ D E T E R M I N A N T
01392  *
01393  *      Calculates the determinant of the 4X4 matrix
01394  */
01395 fastf_t
01396 bn_mat_determinant(const mat_t m)
01397 {
01398         fastf_t det[4];
01399         fastf_t sum;
01400 
01401         det[0] = m[5] * (m[10]*m[15] - m[11]*m[14])
01402                 -m[6] * (m[ 9]*m[15] - m[11]*m[13])
01403                 +m[7] * (m[ 9]*m[14] - m[10]*m[13]);
01404 
01405         det[1] = m[4] * (m[10]*m[15] - m[11]*m[14])
01406                 -m[6] * (m[ 8]*m[15] - m[11]*m[12])
01407                 +m[7] * (m[ 8]*m[14] - m[10]*m[12]);
01408 
01409         det[2] = m[4] * (m[ 9]*m[15] - m[11]*m[13])
01410                 -m[5] * (m[ 8]*m[15] - m[11]*m[12])
01411                 +m[7] * (m[ 8]*m[13] - m[ 9]*m[12]);
01412 
01413         det[3] = m[4] * (m[ 9]*m[14] - m[10]*m[13])
01414                 -m[5] * (m[ 8]*m[14] - m[10]*m[12])
01415                 +m[6] * (m[ 8]*m[13] - m[ 9]*m[12]);
01416 
01417         sum = m[0]*det[0] - m[1]*det[1] + m[2]*det[2] - m[3]*det[3];
01418 
01419         return( sum );
01420 
01421 }
01422 
01423 /**
01424  *
01425  */
01426 int
01427 bn_mat_is_non_unif(const mat_t m)
01428 {
01429     double mag[3];
01430 
01431     mag[0] = MAGSQ(m);
01432     mag[1] = MAGSQ(&m[4]);
01433     mag[2] = MAGSQ(&m[8]);
01434 
01435     if (fabs(1.0 - (mag[1]/mag[0])) > .0005 ||
01436         fabs(1.0 - (mag[2]/mag[0])) > .0005) {
01437 
01438         return 1;
01439     }
01440 
01441     if (m[12] != 0.0 || m[13] != 0.0 || m[14] != 0.0)
01442         return 2;
01443 
01444     return 0;
01445 }
01446 /*@}*/
01447 /*
01448  * Local Variables:
01449  * mode: C
01450  * tab-width: 8
01451  * c-basic-offset: 4
01452  * indent-tabs-mode: t
01453  * End:
01454  * ex: shiftwidth=4 tabstop=8
01455  */

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