Biomechanical Joint Model
 Author: Anderson Maciel

geom.cpp

Go to the documentation of this file.
00001 /*@#-------------------------------------------------------------------
00002  PROJECT            : ESPRIT 6709                              HUMANOID
00003  MODULE             : HUMAN DATA STRUCTURE
00004 
00005  FILE               : geom.c
00006  CREATION DATE      : 01.93
00007  CREATION AUTHOR(S) : R. Boulic
00008  ----------------------------------------------------------------------
00009  KEYWORD(S)         : MatriX, MR3D, VT3D, QUATERNION, VHOM
00010  DEFINED TYPE(S)    : 
00011  RELATED TYPE(S)    : 
00012 
00013  FUNCTIONALITY      :  low level geometric transformations
00014         
00015   ----------------------------------------------------------------------
00016  LANGAGE            : ANSI-C
00017  SYSTEM             : UNIX V 4. / SGI
00018  GRAPHIC LIBRARY    : SGI GL  
00019  ----------------------------------------------------------------------
00020  PROJECT DIRECTOR   : D. THALMANN
00021  LAB                : EPFL- LIG
00022  ------------------------------------------------------------------#@*/
00023 
00024 //#include "geom.h"
00025 #include <libgeom/geom.h>
00026 #include "stdlib.h"
00027 
00028 /*
00029 ** -------------------------------------
00030 ** -- Include of Header files ----------
00031 ** -------------------------------------
00032 */
00033 
00034 #include <stdio.h>
00035 #include <math.h>
00036 #include <assert.h>
00037 
00038 //#ifdef _WIN32
00039 /* Useful constants */
00040 #define M_E                     2.7182818284590452354
00041 #define M_LOG2E         1.4426950408889634074
00042 #define M_LOG10E        0.43429448190325182765
00043 #define M_LN2           0.69314718055994530942
00044 #define M_LN10          2.30258509299404568402
00045 #define M_PI            3.14159265358979323846
00046 #define M_PI_2          1.57079632679489661923
00047 #define M_PI_4          0.78539816339744830962
00048 #define M_1_PI          0.31830988618379067154
00049 #define M_2_PI          0.63661977236758134308
00050 #define M_2_SQRTPI      1.12837916709551257390
00051 #define M_SQRT2         1.41421356237309504880
00052 #define M_SQRT1_2       0.70710678118654752440
00053 
00054 #define fsin            sin
00055 #define fcos            cos
00056 #define ftan            tan
00057 #define fasin           asin
00058 #define facos           acos
00059 #define fatan           atan
00060 #define fatan2          atan2
00061 #define fsqrt           sqrt
00062 //#endif
00063 
00064 #define DEBUG_GEOM      false
00065 
00066 #define SEUIL_GREV1     0.01
00067 
00068 /*                                                                      */
00069 /*   -> matrices 3x3 correspondant aux 6 transformations (initiales)    */
00070 /*      standards et vecteur "null".                                    */
00071 /*      Attention : les matrices sont repesentees avec des vect-ligne   */
00072 /*                                                                      */
00073 /*      | image de x |                  a cause des procedures          */
00074 /*      | image de y |                  cablees de l'iris4d             */
00075 /*      | image de z |                                                  */
00076 
00077 
00078 
00079 
00080 /*
00081 ** -------------------------------------
00082 ** -- STATIC Functions -----------------
00083 ** -------------------------------------
00084 */
00085 
00086 static void nrerror(char *error_text);  
00087 static double **matmxn_convert(double *a,int nrl,int nrh,int ncl,int nch);      
00088 static void Jinv(double *w,int n,double damping);
00089 static void svd(double *a,int m,int n,double *w,double *v); 
00090 static double pythag(double a,double b);
00091 
00092 
00093 /*@$-------------------------------------------------------------------
00094     Static  FUNCTION: 
00095     FUNCTIONALITY   : 
00096     KEYWORD(S)      : 
00097     -------------------------------------------------------------------
00098     FUNCTION TYPE   : void
00099     here parameter description with : flow / name / functionality  
00100     the flow can be one of  IN / OUT / IO (for IN and OUT)
00101     ---------------------------------------------------------------$@*/
00102 
00103 static void nrerror(char *error_text)   
00104 {
00105    fprintf(stderr,"Numerical Recipes run-time error...\n");
00106    fprintf(stderr,"%s\n",error_text);
00107    fprintf(stderr,"...now exiting to system...\n");
00108    exit(1);
00109 }
00110 
00111 /*------------------------------------------------------*/
00112 
00113 static double **matmxn_convert(double *a,int nrl,int nrh,
00114                                int ncl,int nch) 
00115 /* allocate a double matrix m[nrl..nrh][ncl..nch] that points to the matrix
00116 declared in the standard C manner as a[nrow][ncol], where nrow=nrh-nrl+1
00117 and ncol=nch-ncl+1. The routine should be called with the address
00118 &a[0][0] as the first argument. */
00119 {
00120   int i,j,nrow,ncol;
00121   double **m;
00122   
00123   nrow=nrh-nrl+1;
00124   ncol=nch-ncl+1;               
00125                                 /* allocate pointers to rows */
00126   if ((m=(double **) malloc((unsigned) (nrow)*sizeof(double*))) == NULL)
00127     nrerror("allocation failure in matmxn_convert()");
00128   m -= nrl;
00129   
00130                                 /* set pointers to rows */
00131   for(i=0,j=nrl;i<=nrow-1;i++,j++) m[j]=a+ncol*i-ncl;
00132                                 /* return pointer to array of pointers to rows */
00133   return m;
00134 }
00135 
00136 /* ------------------------------------------------------ */
00137 
00138 static void svd(double *a,int m,int n,double *w,double *v) 
00139 {
00140   double **aa,*ww,**vv;
00141   
00142   aa = matmxn_convert(a,1,m,1,n);
00143   ww = w-1;
00144   vv = matmxn_convert(v,1,n,1,n);
00145   
00146   geom::matmxn_svdcmp(aa,m,n,ww,vv);
00147   
00148                                 /* free a matrix allocated by matmxn_convert() */
00149   free((char*) (aa+1));
00150   free((char*) (vv+1));
00151 }
00152 
00153 /*------------------------------------------------------*/
00154 
00155 void Jinv(double *w,int n,double damping) 
00156      /* damping = 1/maxTeta where maxTeta is maximum allowed norm */
00157      /* of rotation vector */
00158 {
00159 #define BIG_W            1.0E+19
00160 #define W_MIN_OVER_W_MAX 0.0001    /* 1.0E-4 */
00161 #define W_PREC           1.0E-10   /* absolute minimum limit for sing. val. */
00162 
00163   int i;
00164   double den;                   /* 'denominateur', auxiliary var. */
00165   double lambda;                /* f(lambda) = maxi. allowed val. for sing. values */
00166   double wmin;                  /* smallest singular value */
00167   double wmax;                  /* largest singular value */
00168   double weps;                  /* percentage of wmax */
00169   
00170   /*
00171   ** -- Find bigger singular value
00172   */
00173   wmax = 0.0;
00174   for (i=0;i<n;i++) 
00175    {
00176      if (w[i] > wmax) 
00177        wmax = w[i]; 
00178    } 
00179   
00180   /*
00181   ** -- Clamp to 0 the singular values smaller than `weps'
00182   */
00183   weps = wmax*W_MIN_OVER_W_MAX; 
00184   wmin = wmax;
00185 
00186   if (weps < W_PREC)   /* Absolute limit for weps, to take care      */
00187     weps = W_PREC;     /* of numerical errors near the 0 (march 98). */
00188 
00189   for (i=0;i<n;i++) 
00190    {
00191      if (w[i] < weps) 
00192        w[i] = 0.0;
00193      if (w[i] >= weps && w[i]<wmin) 
00194        wmin = w[i];                        
00195    }
00196 
00197    /*
00198    ** -- Find lambda
00199    */
00200   lambda = wmin*(damping-wmin);
00201   if (lambda <= 0.0) 
00202    {
00203      lambda = 0.0;              
00204    } 
00205   else 
00206    {
00207      lambda = sqrt(lambda);
00208      if (lambda>=wmin) 
00209        lambda = 0.5 * damping;
00210    }
00211 
00212   for (i=0;i<n;i++) 
00213    {
00214      if (w[i]>BIG_W) 
00215       {
00216         w[i] = 1.0/w[i];
00217       } 
00218      else 
00219       {
00220         den = (w[i]*w[i]+lambda*lambda);
00221         if (den>0.0) 
00222           w[i] /= den;
00223       }
00224    }
00225   
00226 # undef BIG_W 
00227 # undef W_MIN_OVER_W_MAX 
00228 }
00229 
00230 /*------------------------------------------------------*/
00231 
00232 static double pythag(double a,double b) 
00233      /* computes sqrt(a^2+b^2) N.-R. 2nd edition */
00234 {
00235   double absa = fabs(a);
00236   double absb = fabs(b);
00237   
00238   if (absa > absb)
00239     return absa * sqrt(1+(absb*absb)/(absa*absa));
00240   else
00241     return (absb == 0.0 ? 0.0 : absb * sqrt(1+(absa*absa)/(absb*absb)));
00242 }
00243 
00244 
00245 /*
00246 ** -------------------------------------
00247 ** -- Public Functions -----------------
00248 ** -------------------------------------
00249 */
00250 
00251 namespace geom {
00252 
00253  double safe_acos (double f)
00254 
00255  { return f >= 1. ? 0. :
00256           f <= -1. ? M_PI : acos (f);
00257  }
00258 
00259 
00260  double safe_asin (double f)
00261 
00262  { return f >= 1. ? M_PI_2 :
00263           f <= -1. ? -M_PI_2 : asin (f);
00264  }
00265 
00266 /*-------------------------------------------------------------------*/
00267 /*-------------------------------------------------------------------*/
00268 /*-------------------------------------------------------------------*/
00269 
00270 void    matrix_idt_(MatriX matrix)
00271 {
00272         register LIBGEOM_REAL   *m ;
00273 
00274         m = (LIBGEOM_REAL*)matrix ; 
00275 
00276         *(m++) = 1.     ; *(m++) = 0.     ; *(m++) = 0.     ; *(m++) = 0. ;
00277         *(m++) = 0.     ; *(m++) = 1.     ; *(m++) = 0.     ; *(m++) = 0. ;
00278         *(m++) = 0.     ; *(m++) = 0.     ; *(m++) = 1.     ; *(m++) = 0. ;
00279         *(m++) = 0.     ; *(m++) = 0.     ; *(m++) = 0.     ; *m     = 1. ;
00280 }
00281 
00282 
00283 /*-------------------------------------------------------------------*/
00284 void    matrix_copy(const MatriX src, MatriX    dst)
00285 {
00286         register    LIBGEOM_REAL        *ms , *md ;
00287 
00288         ms = (LIBGEOM_REAL*)src ; md = (LIBGEOM_REAL*)dst ; 
00289 
00290         *(md++)=*(ms++); *(md++)=*(ms++); *(md++)=*(ms++); *(md++)=*(ms++); 
00291         *(md++)=*(ms++); *(md++)=*(ms++); *(md++)=*(ms++); *(md++)=*(ms++); 
00292         *(md++)=*(ms++); *(md++)=*(ms++); *(md++)=*(ms++); *(md++)=*(ms++); 
00293         *(md++)=*(ms++); *(md++)=*(ms++); *(md++)=*(ms++); *md    =*ms; 
00294 }
00295 
00296 
00297 /*-------------------------------------------------------------------*/
00298 
00299 void    matrix_compose(const MR3D       mr, 
00300                        const VT3D       vt, 
00301                        MatriX   matrix)
00302 {
00304         matrix[0][0] = mr[0][0] ; matrix[0][1] = mr[0][1] ; 
00305         matrix[0][2] = mr[0][2] ; matrix[0][3] = 0. ;
00306         matrix[1][0] = mr[1][0] ; matrix[1][1] = mr[1][1] ; 
00307         matrix[1][2] = mr[1][2] ; matrix[1][3] = 0. ;
00308         matrix[2][0] = mr[2][0] ; matrix[2][1] = mr[2][1] ; 
00309         matrix[2][2] = mr[2][2] ; matrix[2][3] = 0. ;
00310         matrix[3][0] = vt[0] ; matrix[3][1] = vt[1] ; matrix[3][2] = vt[2]; 
00311         matrix[3][3] = 1. ;
00312 }
00313 
00314 
00315 /*-------------------------------------------------------------------*/
00316 
00317 void    matrix_decompose(MR3D       mr, 
00318                          VT3D       vt, 
00319                          const MatriX       matrix)
00320 {
00322   mr[0][0] = matrix[0][0]; mr[0][1] = matrix[0][1]; mr[0][2] = matrix[0][2];
00323   mr[1][0] = matrix[1][0]; mr[1][1] = matrix[1][1]; mr[1][2] = matrix[1][2]; 
00324   mr[2][0] = matrix[2][0]; mr[2][1] = matrix[2][1]; mr[2][2] = matrix[2][2]; 
00325   vt[0] = matrix[3][0] ; vt[1] = matrix[3][1] ; vt[2] = matrix[3][2]; 
00326 }
00327 
00328 /*-------------------------------------------------------------------*/
00329 
00330 void    matrix_transpose(const MatriX   a,
00331                          MatriX at)
00332 {
00333         int     i, j;
00334 
00335         for(i=0 ; i< 4 ; i++)
00336         {
00337           at [i][i] = a [i][i];
00338 
00339           for(j=i+1 ; j< 4 ; j++)
00340           {
00341             LIBGEOM_REAL tmp = a [i][j];
00342 
00343             at [i][j] = a [j][i];
00344             at [j][i] = tmp;
00345           }
00346         }
00347 }
00348 
00349 /*-------------------------------------------------------------------*/
00350 
00351 void matrix_rotpart(MatriX_t In, MatriX_t Res)
00352 {
00353   int i, j;
00354   
00355   for (i = 0; i < 4; i++)
00356    for (j = 0; j < 4; j++)
00357     {
00358       if (i != 3 && j != 3)
00359        Res[i][j] = In[i][j];
00360       else
00361        Res[i][j] = 0.0;
00362     }
00363   Res[3][3] = 1.0;
00364 }
00365 
00366 /*-------------------------------------------------------------------*/
00367 /* Multiplication d'un vecteur homogene par une matrice homogene u*a->v */
00368 
00369 void    matrix_mult_vhom(const MatriX       a, 
00370                          const VHOM         u,
00371                          VHOM       v)
00372 {
00373         VHOM    w;
00374         int     jcol,k;
00375 
00376         for(jcol=0 ; jcol<3 ; jcol++) 
00377         {
00378           w[jcol] = 0. ;
00379           for(k=0 ; k<4 ; k++) w[jcol] += u[k]*a[k][jcol] ;
00380         }
00381         w[3] = 1. ;
00382 
00383         for(jcol=0 ; jcol<4 ; jcol++) v[jcol] = w[jcol] ;  
00384 }
00385 
00386 
00387 /*-------------------------------------------------------------------*/
00388 /* Mult. d'un vecteur 3D par une matrice homogene u*a->v  (15.3.93)     */
00389 
00390 void    matrix_mult_vt3d(const MatriX       ma, 
00391                          const VT3D         vu,
00392                          VT3D       vv)
00393 {
00394   if(vu != vv)
00395   {
00397     vv[0] = vu[0] * ma[0][0] + vu[1] * ma[1][0] + vu[2] * ma[2][0] + ma[3][0];
00398     vv[1] = vu[0] * ma[0][1] + vu[1] * ma[1][1] + vu[2] * ma[2][1] + ma[3][1];
00399     vv[2] = vu[0] * ma[0][2] + vu[1] * ma[1][2] + vu[2] * ma[2][2] + ma[3][2];
00400   }
00401   else
00402   {
00404     static      VT3D    vw;
00405     vw[0] = vu[0] * ma[0][0] + vu[1] * ma[1][0] + vu[2] * ma[2][0] + ma[3][0];
00406     vw[1] = vu[0] * ma[0][1] + vu[1] * ma[1][1] + vu[2] * ma[2][1] + ma[3][1];
00407     vw[2] = vu[0] * ma[0][2] + vu[1] * ma[1][2] + vu[2] * ma[2][2] + ma[3][2];
00408     
00409     vv[0] = vw[0];
00410     vv[1] = vw[1];
00411     vv[2] = vw[2];
00412   }
00413 }
00414 
00415 
00416 /*-------------------------------------------------------------------*/
00417 void    matrix_inverse(const MatriX         mdir,
00418                        MatriX       minv)
00419 {
00421   if(minv != mdir)
00422   {
00424     minv[0][0] = mdir[0][0]; minv[0][1] = mdir[1][0]; minv[0][2] = mdir[2][0]; 
00425     minv[1][0] = mdir[0][1]; minv[1][1] = mdir[1][1]; minv[1][2] = mdir[2][1]; 
00426     minv[2][0] = mdir[0][2]; minv[2][1] = mdir[1][2]; minv[2][2] = mdir[2][2];
00428     minv[0][3] = minv[1][3] = minv[2][3] = 0.0f; minv[3][3] = 1.0f;
00429     
00431     minv[3][0] = -mdir[3][0] * minv[0][0] -mdir[3][1] * minv[1][0] 
00432       - mdir[3][2] * minv[2][0];
00433     minv[3][1] = -mdir[3][0] * minv[0][1] -mdir[3][1] * minv[1][1] 
00434       - mdir[3][2] * minv[2][1];
00435     minv[3][2] = -mdir[3][0] * minv[0][2] -mdir[3][1] * minv[1][2]
00436       - mdir[3][2] * minv[2][2];
00437   }
00438   else
00439   {
00441     register LIBGEOM_REAL mr, mr1, mr2;
00442     mr = minv[0][1]; minv[0][1] = minv[1][0]; minv[1][0] = mr;
00443     mr = minv[0][2]; minv[0][2] = minv[2][0]; minv[2][0] = mr;
00444     mr = minv[2][1]; minv[2][1] = minv[1][2]; minv[1][2] = mr;
00445     
00449     mr =  mdir[3][0] * mdir[0][0] +mdir[3][1] * mdir[1][0] 
00450       + mdir[3][2] * mdir[2][0];
00451     mr1 = mdir[3][0] * mdir[0][1] +mdir[3][1] * mdir[1][1] 
00452       + mdir[3][2] * mdir[2][1];
00453     mr2 = mdir[3][0] * mdir[0][2] +mdir[3][1] * mdir[1][2]
00454       + mdir[3][2] * mdir[2][2];
00455     minv[3][0] = -mr;
00456     minv[3][1] = -mr1;
00457     minv[3][2] = -mr2;
00458   }
00459 }
00460 
00461 /*--------------------------------------------------------------------*/
00462 /*  Calcul de l'inverse d'une matrice homogene                           */
00463 
00464 void matrix_inverse_det(MatriX res, LIBGEOM_REAL determinant, const MatriX source)
00465 {
00466   MatriX   inv;
00467   int          i, j;
00468   LIBGEOM_REAL        scale;
00469 
00470   /*
00471   ** -- Attention: la matrice est supposee inversible!
00472   */
00473   scale = 1.0 / determinant;
00474 
00475   for (i = GEOM_X_INDEX; i <= GEOM_W_INDEX; ++i) {
00476     for (j = GEOM_X_INDEX; j <= GEOM_W_INDEX; ++j) {
00477       inv[i][j] = matrix_cofactor(source, j, i) * scale;
00478     }
00479   }
00480 
00481   matrix_copy(inv, res);
00482 
00483 }
00484 
00485 /*--------------------------------------------------------------------*/
00486 /*       Calcul d'un cofacteur d'une matrice homogene                    */
00487 
00488 LIBGEOM_REAL matrix_cofactor(const MatriX matrix, int i, int j)
00489 {
00490   MatriX      mij;
00491   int             i1, j1, i2, j2;
00492   static LIBGEOM_REAL    factorsign[] = { 1.0, -1.0, 1.0, -1.0 };
00493       
00494   matrix_idt_(mij);
00495 
00496   i1 = GEOM_X_INDEX;
00497   for (i2 = GEOM_X_INDEX; i2 < GEOM_W_INDEX; ++i2) {
00498     if (i1 == i) ++i1;
00499 
00500     j1 = GEOM_X_INDEX;
00501     for (j2 = GEOM_X_INDEX; j2 < GEOM_W_INDEX; ++j2) {
00502       if (j1 == j) ++j1;
00503 
00504       mij[i2][j2] = matrix[i1][j1];
00505       ++j1;
00506     }
00507     ++i1;   
00508   }
00509 
00510   return (factorsign[i] * factorsign[j] * matrix_determinant(mij)); 
00511 } 
00512 
00513 /*-------------------------------------------------------------------*/
00514 /*    Calcul du determinant d'une matrice homogene                      */
00515 
00516 LIBGEOM_REAL matrix_determinant(const MatriX matrix)
00517 {
00518 
00519   LIBGEOM_REAL det;
00520 
00521   det =   
00522     matrix[GEOM_X_INDEX][GEOM_X_INDEX] * 
00523     ( matrix[GEOM_Y_INDEX][GEOM_Y_INDEX] * 
00524       matrix[GEOM_Z_INDEX][GEOM_Z_INDEX] * 
00525       matrix[GEOM_W_INDEX][GEOM_W_INDEX]
00526     + matrix[GEOM_Y_INDEX][GEOM_Z_INDEX] * 
00527       matrix[GEOM_Z_INDEX][GEOM_W_INDEX] * 
00528       matrix[GEOM_W_INDEX][GEOM_Y_INDEX]
00529     + matrix[GEOM_Y_INDEX][GEOM_W_INDEX] * 
00530       matrix[GEOM_Z_INDEX][GEOM_Y_INDEX] * 
00531       matrix[GEOM_W_INDEX][GEOM_Z_INDEX]
00532     - matrix[GEOM_W_INDEX][GEOM_Y_INDEX] * 
00533       matrix[GEOM_Z_INDEX][GEOM_Z_INDEX] * 
00534       matrix[GEOM_Y_INDEX][GEOM_W_INDEX]
00535     - matrix[GEOM_W_INDEX][GEOM_Z_INDEX] * 
00536       matrix[GEOM_Z_INDEX][GEOM_W_INDEX] * 
00537       matrix[GEOM_Y_INDEX][GEOM_Y_INDEX]
00538     - matrix[GEOM_W_INDEX][GEOM_W_INDEX] *
00539       matrix[GEOM_Z_INDEX][GEOM_Y_INDEX] *
00540       matrix[GEOM_Y_INDEX][GEOM_Z_INDEX] ) -
00541     matrix[GEOM_X_INDEX][GEOM_Y_INDEX] * 
00542     ( matrix[GEOM_Y_INDEX][GEOM_X_INDEX] *
00543       matrix[GEOM_Z_INDEX][GEOM_Z_INDEX] *
00544       matrix[GEOM_W_INDEX][GEOM_W_INDEX]
00545     + matrix[GEOM_Y_INDEX][GEOM_Z_INDEX] *
00546       matrix[GEOM_Z_INDEX][GEOM_W_INDEX] *
00547       matrix[GEOM_W_INDEX][GEOM_X_INDEX]
00548     + matrix[GEOM_Y_INDEX][GEOM_W_INDEX] *
00549       matrix[GEOM_Z_INDEX][GEOM_X_INDEX] *
00550       matrix[GEOM_W_INDEX][GEOM_Z_INDEX]
00551     - matrix[GEOM_W_INDEX][GEOM_X_INDEX] *
00552       matrix[GEOM_Z_INDEX][GEOM_Z_INDEX] *
00553       matrix[GEOM_Y_INDEX][GEOM_W_INDEX]
00554     - matrix[GEOM_W_INDEX][GEOM_Z_INDEX] *
00555       matrix[GEOM_Z_INDEX][GEOM_W_INDEX] *
00556       matrix[GEOM_Y_INDEX][GEOM_X_INDEX]
00557     - matrix[GEOM_W_INDEX][GEOM_W_INDEX] *
00558       matrix[GEOM_Z_INDEX][GEOM_X_INDEX] *
00559       matrix[GEOM_Y_INDEX][GEOM_Z_INDEX] ) +
00560     matrix[GEOM_X_INDEX][GEOM_Z_INDEX] * 
00561     ( matrix[GEOM_Y_INDEX][GEOM_X_INDEX] *
00562       matrix[GEOM_Z_INDEX][GEOM_Y_INDEX] *
00563       matrix[GEOM_W_INDEX][GEOM_W_INDEX]
00564     + matrix[GEOM_Y_INDEX][GEOM_Y_INDEX] *
00565       matrix[GEOM_Z_INDEX][GEOM_W_INDEX] *
00566       matrix[GEOM_W_INDEX][GEOM_X_INDEX]
00567     + matrix[GEOM_Y_INDEX][GEOM_W_INDEX] *
00568       matrix[GEOM_Z_INDEX][GEOM_X_INDEX] *
00569       matrix[GEOM_W_INDEX][GEOM_Y_INDEX]
00570     - matrix[GEOM_W_INDEX][GEOM_X_INDEX] *
00571       matrix[GEOM_Z_INDEX][GEOM_Y_INDEX] *
00572       matrix[GEOM_Y_INDEX][GEOM_W_INDEX]
00573     - matrix[GEOM_W_INDEX][GEOM_Y_INDEX] *
00574       matrix[GEOM_Z_INDEX][GEOM_W_INDEX] *
00575       matrix[GEOM_Y_INDEX][GEOM_X_INDEX]
00576     - matrix[GEOM_W_INDEX][GEOM_W_INDEX] *
00577       matrix[GEOM_Z_INDEX][GEOM_X_INDEX] *
00578       matrix[GEOM_Y_INDEX][GEOM_Y_INDEX] ) -
00579     matrix[GEOM_X_INDEX][GEOM_W_INDEX] * 
00580     ( matrix[GEOM_Y_INDEX][GEOM_X_INDEX] *
00581       matrix[GEOM_Z_INDEX][GEOM_Y_INDEX] *
00582       matrix[GEOM_W_INDEX][GEOM_Z_INDEX]
00583     + matrix[GEOM_Y_INDEX][GEOM_Y_INDEX] *
00584       matrix[GEOM_Z_INDEX][GEOM_Z_INDEX] *
00585       matrix[GEOM_W_INDEX][GEOM_X_INDEX]
00586     + matrix[GEOM_Y_INDEX][GEOM_Z_INDEX] *
00587       matrix[GEOM_Z_INDEX][GEOM_X_INDEX] *
00588       matrix[GEOM_W_INDEX][GEOM_Y_INDEX]
00589     - matrix[GEOM_W_INDEX][GEOM_X_INDEX] *
00590       matrix[GEOM_Z_INDEX][GEOM_Y_INDEX] *
00591       matrix[GEOM_Y_INDEX][GEOM_Z_INDEX]
00592     - matrix[GEOM_W_INDEX][GEOM_Y_INDEX] * 
00593       matrix[GEOM_Z_INDEX][GEOM_Z_INDEX] *
00594       matrix[GEOM_Y_INDEX][GEOM_X_INDEX]
00595     - matrix[GEOM_W_INDEX][GEOM_Z_INDEX] *
00596       matrix[GEOM_Z_INDEX][GEOM_X_INDEX] *
00597       matrix[GEOM_Y_INDEX][GEOM_Y_INDEX] );
00598 
00599   return det;  
00600 }
00601 
00602 /*-------------------------------------------------------------------*/
00603 /*      effectue le produit matriciel ma*mb et range le resultat dans mc*/
00604 
00605 
00606 #define matrix_is_affine(m) ((m [0][3] == 0.) && (m [1][3] == 0.) && \
00607                              (m [2][3] == 0.) && (m [3][3] == 1.))
00608 
00609 void matrix_mult (const MatriX ma,
00610                   const MatriX mb,
00611                   MatriX mc)
00612 
00613 {
00614   if (matrix_is_affine (ma) && matrix_is_affine (mb))
00615   {
00616     register LIBGEOM_REAL *a , *b , *c;
00617 
00618     LIBGEOM_REAL a00 , a01 , a02 ,
00619         a10 , a11 , a12 ,
00620         a20 , a21 , a22 ,
00621         a30 , a31 , a32 ,
00622 
00623         b00 , b01 , b02 ,
00624         b10 , b11 , b12 ,
00625         b20 , b21 , b22 ,
00626         b30 , b31 , b32 ;
00627 
00628         a = (LIBGEOM_REAL*) ma;
00629         b = (LIBGEOM_REAL*) mb;
00630         c = (LIBGEOM_REAL*) mc; 
00631 
00632         a00 = *(a++) ; a01 = *(a++) ; a02 = *(a++) ;  a++ ;
00633         a10 = *(a++) ; a11 = *(a++) ; a12 = *(a++) ;  a++ ;
00634         a20 = *(a++) ; a21 = *(a++) ; a22 = *(a++) ;  a++ ;
00635         a30 = *(a++) ; a31 = *(a++) ; a32 = *a ;
00636 
00637         b00 = *(b++) ; b01 = *(b++) ; b02 = *(b++) ; b++ ;
00638         b10 = *(b++) ; b11 = *(b++) ; b12 = *(b++) ; b++ ;
00639         b20 = *(b++) ; b21 = *(b++) ; b22 = *(b++) ; b++ ;
00640         b30 = *(b++) ; b31 = *(b++) ; b32 = *b ;
00641 
00642         *(c++) = a00 * b00  +  a01 * b10  +  a02 * b20  ;
00643         *(c++) = a00 * b01  +  a01 * b11  +  a02 * b21  ;
00644         *(c++) = a00 * b02  +  a01 * b12  +  a02 * b22  ;
00645         *(c++) = 0. ;
00646 
00647         *(c++) = a10 * b00  +  a11 * b10  +  a12 * b20  ;
00648         *(c++) = a10 * b01  +  a11 * b11  +  a12 * b21  ;
00649         *(c++) = a10 * b02  +  a11 * b12  +  a12 * b22  ;
00650         *(c++) = 0. ;
00651 
00652         *(c++) = a20 * b00  +  a21 * b10  +  a22 * b20  ;
00653         *(c++) = a20 * b01  +  a21 * b11  +  a22 * b21  ;
00654         *(c++) = a20 * b02  +  a21 * b12  +  a22 * b22  ;
00655         *(c++) = 0. ;
00656 
00657         *(c++) = a30 * b00  +  a31 * b10  +  a32 * b20 + b30 ;
00658         *(c++) = a30 * b01  +  a31 * b11  +  a32 * b21 + b31 ;
00659         *(c++) = a30 * b02  +  a31 * b12  +  a32 * b22 + b32 ;
00660         *(c)   = 1. ;
00661   }
00662   else /* version for general case, seldom used -> no optimisation */
00663   {
00664     int    i, j;
00665     MatriX mt;
00666 
00667     for (i=0; i < 4; i++)
00668       for (j=0; j < 4; j++)
00669         mt [i][j] = ma [i][0] * mb [0][j] +
00670                     ma [i][1] * mb [1][j] +
00671                     ma [i][2] * mb [2][j] +
00672                     ma [i][3] * mb [3][j];
00673 
00674     matrix_copy (mt, mc);
00675   }
00676 }
00677 /*-------------------------------------------------------------------*/
00678 /*  pour des matrices affines seulement : usage reserve              */
00679 /*  effectue le produit matriciel ma*mb et range le resultat dans mc*/
00680 
00681 
00682 void matrix_mult_opt (const MatriX ma, const MatriX mb, MatriX mc)
00683 
00684 {  
00685   register LIBGEOM_REAL *a , *b , *c;
00686 
00687   LIBGEOM_REAL a00 , a01 , a02 ,
00688         a10 , a11 , a12 ,
00689         a20 , a21 , a22 ,
00690         a30 , a31 , a32 ,
00691 
00692         b00 , b01 , b02 ,
00693         b10 , b11 , b12 ,
00694         b20 , b21 , b22 ,
00695         b30 , b31 , b32 ;
00696 
00697         a = (LIBGEOM_REAL*) ma;
00698         b = (LIBGEOM_REAL*) mb;
00699         c = (LIBGEOM_REAL*) mc; 
00700 
00701         a00 = *(a++) ; a01 = *(a++) ; a02 = *(a++) ;  a++ ;
00702         a10 = *(a++) ; a11 = *(a++) ; a12 = *(a++) ;  a++ ;
00703         a20 = *(a++) ; a21 = *(a++) ; a22 = *(a++) ;  a++ ;
00704         a30 = *(a++) ; a31 = *(a++) ; a32 = *a ;
00705 
00706         b00 = *(b++) ; b01 = *(b++) ; b02 = *(b++) ; b++ ;
00707         b10 = *(b++) ; b11 = *(b++) ; b12 = *(b++) ; b++ ;
00708         b20 = *(b++) ; b21 = *(b++) ; b22 = *(b++) ; b++ ;
00709         b30 = *(b++) ; b31 = *(b++) ; b32 = *b ;
00710 
00711         *(c++) = a00 * b00  +  a01 * b10  +  a02 * b20  ;
00712         *(c++) = a00 * b01  +  a01 * b11  +  a02 * b21  ;
00713         *(c++) = a00 * b02  +  a01 * b12  +  a02 * b22  ;
00714         *(c++) = 0. ;
00715 
00716         *(c++) = a10 * b00  +  a11 * b10  +  a12 * b20  ;
00717         *(c++) = a10 * b01  +  a11 * b11  +  a12 * b21  ;
00718         *(c++) = a10 * b02  +  a11 * b12  +  a12 * b22  ;
00719         *(c++) = 0. ;
00720 
00721         *(c++) = a20 * b00  +  a21 * b10  +  a22 * b20  ;
00722         *(c++) = a20 * b01  +  a21 * b11  +  a22 * b21  ;
00723         *(c++) = a20 * b02  +  a21 * b12  +  a22 * b22  ;
00724         *(c++) = 0. ;
00725 
00726         *(c++) = a30 * b00  +  a31 * b10  +  a32 * b20 + b30 ;
00727         *(c++) = a30 * b01  +  a31 * b11  +  a32 * b21 + b31 ;
00728         *(c++) = a30 * b02  +  a31 * b12  +  a32 * b22 + b32 ;
00729         *(c)   = 1. ;
00730 }
00731 
00732 /*-------------------------------------------------------------------*/
00733 bool    matrix_egalite(const MatriX     a,
00734                        const MatriX     b)
00735 {
00736         MR3D    mra,mrb;
00737         VT3D    vta,vtb;
00738 
00739         matrix_decompose(mra,vta,a);
00740         matrix_decompose(mrb,vtb,b);
00741         if(mr3d_egalite(mra,mrb,EPSIL_MR3D)&& vt3d_egalite(vta,vtb,EPSIL_VT3D))
00742           return(true);
00743         else return(false);
00744 }
00745 
00746 /*-------------------------------------------------------------------*/
00747 /* cette procedure cherche a attirer une transformation homogene    */
00748 /* vers l'identite.                                                 */
00749 
00750 int     matrix_attraction_idt(MatriX    a)
00751 {
00752         MR3D    mr ;
00753         VT3D    vt ;
00754         int     result1,result2 ;
00755 
00756         a[0][3] = a[1][3] = a[2][3] = 0. ;
00757         a[3][3] = 1. ;
00758 
00759         matrix_decompose(mr,vt,a);
00760 
00761         result1 = mr3d_attraction_idt(mr,EPSIL_MR3D);
00762         result2 = vt3d_attraction_nul(vt,EPSIL_VT3D);
00763 
00764         if((result1  == ATTRACTION_COMPLETE)&&(result2 == ATTRACTION_COMPLETE))
00765         {
00766           matrix_compose(mr,vt,a);
00767           return(ATTRACTION_COMPLETE);
00768         }
00769 
00770         if((result1  == ATTRACTION_NULLE) && (result2 == ATTRACTION_NULLE))
00771           return(ATTRACTION_NULLE);
00772 
00773         matrix_compose(mr,vt,a);
00774         return(ATTRACTION_PARTIELLE);
00775 }
00776 
00777 /*-------------------------------------------------------------------*/
00778 
00779 int     matrix_proximite(const MatriX       a,
00780                          const MatriX       b, 
00781                          LIBGEOM_REAL       seuil_mr,
00782                          LIBGEOM_REAL       seuil_vt)
00783 {
00784         MR3D    mra,mrb;
00785         VT3D    vta,vtb;
00786         int     proximite;
00787         bool    eqmr,eqvt;
00788 
00789         matrix_decompose(mra,vta,a);
00790         matrix_decompose(mrb,vtb,b);
00791         eqmr = mr3d_egalite(mra,mrb,seuil_mr);
00792         eqvt = vt3d_egalite(vta,vtb,seuil_vt);
00793         if(eqmr && eqvt)        proximite = 0;
00794         else if(eqmr && !eqvt)  proximite = 1;
00795         else if(!eqmr && eqvt)  proximite = 2;
00796         else                    proximite = 3;
00797         return(proximite);
00798 }
00799 
00800 /*-------------------------------------------------------------------*/
00801 
00802 void matrix_lerp (const MatriX_t a, const MatriX_t b, LIBGEOM_REAL u, MatriX result)
00803      /* linear interpolation */
00804      /* result = a to b, when u = 0 to 1 */
00805 {
00806   QUATERNION prevQt;            /* previous quaternion */
00807   QUATERNION crtQt;             /* current quaternion */
00808   QUATERNION newQt;             /* new quaternion */
00809   register LIBGEOM_REAL v;
00810                                 /* interpolate rotation part */
00811   quat_from_matrix(a,prevQt);
00812   quat_from_matrix(b,crtQt);
00813   quat_slerp(prevQt,crtQt,u,newQt);
00814   quat_to_matrix(newQt, result);
00815 
00816                                 /* interpolate translation part */
00817   v = 1-u;                      /* speed up arithmetic */
00818   result[3][0] = v * a[3][0] + u * b[3][0];
00819   result[3][1] = v * a[3][1] + u * b[3][1];
00820   result[3][2] = v * a[3][2] + u * b[3][2];
00821   result[0][3] = 0;
00822   result[1][3] = 0;
00823   result[2][3] = 0;
00824   result[3][3] = 1; 
00825 }
00826 
00827 /*@#-------------------------------------------------------------------
00828     Public FUNCTION : 
00829     FUNCTIONALITY   : write the matrix m in the file f.
00830     KEYWORD(S)      : 
00831     -------------------------------------------------------------------
00832     FUNCTION TYPE   : bool
00833     here parameter description with : flow / name / functionality  
00834     the flow can be one of  IN / OUT / IO (for IN and OUT)
00835     ---------------------------------------------------------------#@*/
00836 bool    matrix_write(const MatriX m, FILE *f)
00837 {
00838   char *format_str;
00839 
00840   if (sizeof(LIBGEOM_REAL) == sizeof(float))
00841     format_str = "%f %f %f %f";
00842   else 
00843     format_str = "%lf %lf %lf %lf";
00844 
00845     if (f)
00846     {
00847         fprintf(f, "\n"); 
00848         fprintf(f, format_str, 
00849                 m[GEOM_X_INDEX][GEOM_X_INDEX], 
00850                 m[GEOM_X_INDEX][GEOM_Y_INDEX], 
00851                 m[GEOM_X_INDEX][GEOM_Z_INDEX], 
00852                 m[GEOM_X_INDEX][GEOM_W_INDEX]);
00853         fprintf(f, "\n"); 
00854         fprintf(f, format_str, 
00855                 m[GEOM_Y_INDEX][GEOM_X_INDEX], 
00856                 m[GEOM_Y_INDEX][GEOM_Y_INDEX], 
00857                 m[GEOM_Y_INDEX][GEOM_Z_INDEX], 
00858                 m[GEOM_Y_INDEX][GEOM_W_INDEX]);
00859         fprintf(f, "\n"); 
00860         fprintf(f, format_str, 
00861                 m[GEOM_Z_INDEX][GEOM_X_INDEX], 
00862                 m[GEOM_Z_INDEX][GEOM_Y_INDEX], 
00863                 m[GEOM_Z_INDEX][GEOM_Z_INDEX], 
00864                 m[GEOM_Z_INDEX][GEOM_W_INDEX]);
00865         fprintf(f, "\n"); 
00866         fprintf(f, format_str, 
00867                 m[GEOM_W_INDEX][GEOM_X_INDEX], 
00868                 m[GEOM_W_INDEX][GEOM_Y_INDEX], 
00869                 m[GEOM_W_INDEX][GEOM_Z_INDEX], 
00870                 m[GEOM_W_INDEX][GEOM_W_INDEX]); 
00871         fprintf(f, "\n"); 
00872         return(true);
00873     }
00874     return(false);
00875 }
00876 
00877 
00878 /*@#-------------------------------------------------------------------
00879     Public FUNCTION : 
00880     FUNCTIONALITY   : read the matrix m from the file f.
00881     KEYWORD(S)      : 
00882     -------------------------------------------------------------------
00883     FUNCTION TYPE   : bool
00884     here parameter description with : flow / name / functionality  
00885     the flow can be one of  IN / OUT / IO (for IN and OUT)
00886     ---------------------------------------------------------------#@*/
00887 bool    matrix_read(MatriX m, FILE *f)
00888 {
00889   char *format_str;
00890 
00891   if (sizeof(LIBGEOM_REAL) == sizeof(float))
00892     format_str = "%f %f %f %f";
00893   else 
00894     format_str = "%lf %lf %lf %lf";
00895 
00896     if (f)
00897     {
00898          
00899         fscanf(f, format_str, &m[GEOM_X_INDEX][GEOM_X_INDEX], 
00900         &m[GEOM_X_INDEX][GEOM_Y_INDEX],&m[GEOM_X_INDEX][GEOM_Z_INDEX],
00901         &m[GEOM_X_INDEX][GEOM_W_INDEX]);
00902          
00903         fscanf(f, format_str, &m[GEOM_Y_INDEX][GEOM_X_INDEX], 
00904         &m[GEOM_Y_INDEX][GEOM_Y_INDEX], &m[GEOM_Y_INDEX][GEOM_Z_INDEX], 
00905         &m[GEOM_Y_INDEX][GEOM_W_INDEX]);
00906          
00907         fscanf(f, format_str, &m[GEOM_Z_INDEX][GEOM_X_INDEX], 
00908         &m[GEOM_Z_INDEX][GEOM_Y_INDEX], &m[GEOM_Z_INDEX][GEOM_Z_INDEX], 
00909         &m[GEOM_Z_INDEX][GEOM_W_INDEX]);
00910          
00911         fscanf(f, format_str, &m[GEOM_W_INDEX][GEOM_X_INDEX], 
00912         &m[GEOM_W_INDEX][GEOM_Y_INDEX], &m[GEOM_W_INDEX][GEOM_Z_INDEX], 
00913         &m[GEOM_W_INDEX][GEOM_W_INDEX]);        
00914          
00915         return(true);
00916     }
00917     return(false);
00918 }
00919 
00920 
00921 /*-------------------------------------------------------------------*/
00922 /*-------------------------------------------------------------------*/
00923 /*-------------------------------------------------------------------*/
00924 
00925 void    mr3d_idt_(MR3D  mr)
00926 {
00928         register LIBGEOM_REAL   *m ;
00929 
00930         m = (LIBGEOM_REAL*)mr ; 
00931 
00932         *(m++) = 1.     ; *(m++) = 0.     ; *(m++) = 0.     ; 
00933         *(m++) = 0.     ; *(m++) = 1.     ; *(m++) = 0.     ; 
00934         *(m++) = 0.     ; *(m++) = 0.     ; *m     = 1.     ; 
00935 }
00936 
00937 /*-------------------------------------------------------------------*/
00938 void    mr3d_get(const MatriX       matrix, 
00939                  MR3D       a)
00940 {
00941   int   i,j;
00942   
00943   for(i=0 ; i<3 ; i++)
00944    for(j=0 ; j<3 ; j++)
00945     a[i][j] = matrix[i][j] ;
00946 }
00947 
00948 /*-------------------------------------------------------------------*/
00949 
00950 void    mr3d_copy(const MR3D src, MR3D dst)
00951 {
00953   dst[0][0] = src[0][0] ; dst[0][1] = src[0][1]   ; dst[0][2] = src[0][2] ; 
00954   dst[1][0] = src[1][0] ; dst[1][1] = src[1][1]   ; dst[1][2] = src[1][2] ; 
00955   dst[2][0] = src[2][0] ; dst[2][1] = src[2][1]   ; dst[2][2] = src[2][2] ;
00956 }
00957 
00958 /*-------------------------------------------------------------------*/
00959 
00960 void    mr3d_load(MatriX    matrix, 
00961                   const MR3D        a)           
00962 {
00963         int     i,j;
00964 
00965         for(i=0 ; i<3 ; i++)
00966           for(j=0 ; j<3 ; j++)
00967               matrix[i][j] = a[i][j] ;
00968 } 
00969 
00970 /*-------------------------------------------------------------------*/
00971 void    mr3d_transpose(const MR3D       ma,
00972                        MR3D     mat)
00973 {
00974   if(ma != mat)
00975   {
00978     mat[0][0] = ma[0][0]; mat[0][1] = ma[1][0]; mat[0][2] = ma[2][0]; 
00979     mat[1][0] = ma[0][1]; mat[1][1] = ma[1][1]; mat[1][2] = ma[2][1]; 
00980     mat[2][0] = ma[0][2]; mat[2][1] = ma[1][2]; mat[2][2] = ma[2][2];
00981   }
00982   else 
00983   { /* self transpose case */    
00985         register    LIBGEOM_REAL        w ;
00986         register    LIBGEOM_REAL        *a ;
00987 
00988         a = (LIBGEOM_REAL*)ma ;
00989 
00990         w = *(a+1) ; *(a+1) = *(a+3) ; *(a+3) = w ;
00991         w = *(a+2) ; *(a+2) = *(a+6) ; *(a+6) = w ;
00992         w = *(a+5) ; *(a+5) = *(a+7) ; *(a+7) = w ;
00993   }
00994 }
00995 
00996 /*-------------------------------------------------------------------*/
00997 void    mr3d_self_transpose(MR3D ma)
00998 {
01000         register    LIBGEOM_REAL        w ;
01001         register    LIBGEOM_REAL        *a ;
01002 
01003         a = (LIBGEOM_REAL*)ma ;
01004 
01005         w = *(a+1) ; *(a+1) = *(a+3) ; *(a+3) = w ;
01006         w = *(a+2) ; *(a+2) = *(a+6) ; *(a+6) = w ;
01007         w = *(a+5) ; *(a+5) = *(a+7) ; *(a+7) = w ;
01008 }
01009 
01010 /*-------------------------------------------------------------------*/
01011 void    mr3d_perm_circ(MR3D     a, 
01012                        MR3D     b)
01013 {
01014         VT3D    v;
01015         int     jcol;
01016         
01017         for(jcol=0 ; jcol<3 ; jcol++)
01018         {
01019           v[jcol]    = a[0][jcol] ;
01020           b[0][jcol] = a[1][jcol] ;
01021           b[1][jcol] = a[2][jcol] ;
01022           b[2][jcol] = v[jcol] ;
01023         }
01024 }
01025 
01026 /*-------------------------------------------------------------------*/
01027 /* "l'oppose" calcule ici n'est pas obtenu en prenant l'oppose de       */
01028 /* chacun des termes de la matrice car on n'obtiendrait pas une base    */
01029 /* droite. On choisit donc de prendre l'oppose du seul vecteur z        */
01030 /* car ce vecteur est privilegie pour la representation du mouvement et */
01031 /* on permutte les vecteurs x et y obtenant ainsi une base droite.      */
01032 
01033 void    mr3d_opposite(MR3D      a, 
01034                       MR3D      b)
01035 {
01036         VT3D    v;
01037         int     jcol;
01038 
01039         for(jcol=0 ; jcol<3 ; jcol++)
01040         {
01041           b[2][jcol] = -a[2][jcol] ;
01042           v[jcol]    =  a[0][jcol] ;
01043           b[0][jcol] =  a[1][jcol] ;
01044           b[1][jcol] =  v[jcol] ;
01045         }
01046 }
01047 
01048 /*-------------------------------------------------------------------*/
01049 /* la "symetrie" calculee ici conserve la coordonnee z et oppose les    */
01050 /* coordonnes x et y . Ce module est complementaire des deux precedents */
01051 /* et permet d'obtenir n'importe qu'elle orientation orthogonale d'une  */
01052 /* base par rapport a une autre en combinant quelques appels .          */
01053 
01054 void    mr3d_symtxy(MR3D        a, 
01055                     MR3D        b)
01056 {
01057         int     jcol;
01058 
01059         for(jcol=0 ; jcol<3 ; jcol++)
01060         {
01061           b[0][jcol] = -a[0][jcol] ;
01062           b[1][jcol] = -a[1][jcol] ;
01063           b[2][jcol] = a[2][jcol] ;
01064         }
01065 }
01066 
01067 /*@#-------------------------------------------------------------------
01068     Public FUNCTION : 
01069     FUNCTIONALITY   : matrix multiplication by scalar
01070     KEYWORD(S)      : 
01071     -------------------------------------------------------------------
01072     FUNCTION TYPE   : void
01073     here parameter description with : flow / name / functionality  
01074     the flow can be one of  IN / OUT / IO (for IN and OUT)
01075     ---------------------------------------------------------------#@*/
01076 void     mr3d_scale (const MR3D self, LIBGEOM_REAL scalar, MR3D res)
01077 {
01078     register int    i, j;
01079     
01080     for (i = GEOM_X_INDEX; i <= GEOM_Z_INDEX; ++i)
01081     {
01082         for (j = GEOM_X_INDEX; j <= GEOM_Z_INDEX; ++j)
01083         {
01084            res[i][j] = scalar * self[i][j];
01085         }
01086     }
01087 }
01088 
01089 /*@#-------------------------------------------------------------------
01090     Public FUNCTION : 
01091     FUNCTIONALITY   : matrix substraction
01092     KEYWORD(S)      : 
01093     -------------------------------------------------------------------
01094     FUNCTION TYPE   : void
01095     here parameter description with : flow / name / functionality  
01096     the flow can be one of  IN / OUT / IO (for IN and OUT)
01097     ---------------------------------------------------------------#@*/
01098 void     mr3d_sub (const MR3D left, const MR3D right, MR3D res)
01099 {
01100     register int    i, j;
01101     
01102     for (i = GEOM_X_INDEX; i <= GEOM_Z_INDEX; ++i)
01103     {
01104         for (j = GEOM_X_INDEX; j <= GEOM_Z_INDEX; ++j)
01105         {
01106            res[i][j] = left[i][j] - right[i][j];
01107         }
01108     }
01109 }
01110 
01111 /*@#-------------------------------------------------------------------
01112     Public FUNCTION : 
01113     FUNCTIONALITY   : matrix addition
01114     KEYWORD(S)      : 
01115     -------------------------------------------------------------------
01116     FUNCTION TYPE   : void
01117     here parameter description with : flow / name / functionality  
01118     the flow can be one of  IN / OUT / IO (for IN and OUT)
01119     ---------------------------------------------------------------#@*/
01120 void     mr3d_add (const MR3D left, const MR3D right, MR3D res)
01121 {
01122     register int    i, j;
01123     
01124     for (i = GEOM_X_INDEX; i <= GEOM_Z_INDEX; ++i)
01125     {
01126         for (j = GEOM_X_INDEX; j <= GEOM_Z_INDEX; ++j)
01127         {
01128            res[i][j] = left[i][j] + right[i][j];
01129         }
01130     }
01131 }
01132 
01133 
01134 /*-------------------------------------------------------------------*/
01135 /* effectue la multiplication des matrices 3x3   :    a*b -> c          */
01136 
01137 void    mr3d_mult(const MR3D  a, const MR3D  b, MR3D  c)
01138 {
01139         MR3D    w;
01140         register int    i,j ;
01141 
01142         for(i=0 ; i<3 ; i++)
01143         {
01144           for(j=0 ; j<3 ; j++)
01145           {
01146             w[i][j] = a [i][0] * b [0][j] + a [i][1] * b [1][j] + a [i][2] * b [2][j];
01147           }
01148         }
01149 
01150         for(i=0 ; i<3 ; i++)
01151           for(j=0 ; j<3 ; j++)
01152             c[i][j] = w[i][j] ;    
01153 }
01154 
01155 /*-------------------------------------------------------------------*/
01156 /* multiplication dans l'espace 3d  u*a  donnant le vecteur v           */
01157 /* version optimisee (ancienne version en commentaire)                  */
01158 
01159 void    mr3d_mult_vt3d(const MR3D           ma,
01160                        const VT3D           vu,
01161                        VT3D         vv)
01162 {
01163   if(vu != vv)
01164   { 
01165     vv[0] = vu[0] * ma[0][0]  +  vu[1] * ma[1][0]   +  vu[2] * ma[2][0];
01166     vv[1] = vu[0] * ma[0][1]  +  vu[1] * ma[1][1]   +  vu[2] * ma[2][1];
01167     vv[2] = vu[0] * ma[0][2]  +  vu[1] * ma[1][2]   +  vu[2] * ma[2][2];
01168   }
01169   else
01170   { 
01171     static      VT3D    vw;
01172  
01173     vw[0] = vu[0] * ma[0][0]  +  vu[1] * ma[1][0]   +  vu[2] * ma[2][0];
01174     vw[1] = vu[0] * ma[0][1]  +  vu[1] * ma[1][1]   +  vu[2] * ma[2][1];
01175     vw[2] = vu[0] * ma[0][2]  +  vu[1] * ma[1][2]   +  vu[2] * ma[2][2];
01176     
01177     vv[0] = vw[0];
01178     vv[1] = vw[1];
01179     vv[2] = vw[2];
01180   }
01181 }
01182 
01183 /*-------------------------------------------------------------------*/
01184 #define EPSILON 1e-4
01185 
01186 /*-------------------------------------------------------------------*/
01187 /* conversion d'un vecteur de rotation en matrice de rotation           */
01188 /* en passant par un quaternion (source toolkit matrix_h.c)             */
01189 
01190 void    mr3d_from_axis_angle(MR3D mr, const VT3D faxis)
01191 {
01192    double    k[3];
01193    double    axis[3];
01194    double    ang;               /* scalar angle of rotation */
01195    double    c, s, v;           /* cosine, sine, versine of ang */
01196 
01197     /* these equations are set up for cw rot. */
01198     axis[0]= (double) faxis[0];
01199     axis[1]= (double) faxis[1];
01200     axis[2]= (double) faxis[2];
01201     
01202    ang = sqrt((axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]));
01203 
01204    if (ang < EPSILON)
01205    {
01206      mr3d_idt_ (mr);
01207 
01208      return;
01209    }
01210 
01211    k[0] = axis[0]/ang ;       /* normalization */
01212    k[1] = axis[1]/ang ;
01213    k[2] = axis[2]/ang ;
01214 
01215    c = cos( ang );             /* in right-handed, ccw rot in left-handed */
01216    s = sin( ang );
01217    v = 1.0 - c;                /* versine(x) = 1 - cos(x) */
01218 
01219    mr[0][0] = (LIBGEOM_REAL) (k[0] * k[0] * v + c);
01220    mr[0][1] = (LIBGEOM_REAL) (k[0] * k[1] * v + k[2] * s);
01221    mr[0][2] = (LIBGEOM_REAL) (k[0] * k[2] * v - k[1] * s);
01222 
01223    mr[1][0] = (LIBGEOM_REAL) (k[1] * k[0] * v - k[2] * s);
01224    mr[1][1] = (LIBGEOM_REAL) (k[1] * k[1] * v + c);
01225    mr[1][2] = (LIBGEOM_REAL) (k[1] * k[2] * v + k[0] * s);
01226 
01227    mr[2][0] = (LIBGEOM_REAL) (k[2] * k[0] * v + k[1] * s);
01228    mr[2][1] = (LIBGEOM_REAL) (k[2] * k[1] * v - k[0] * s);
01229    mr[2][2] = (LIBGEOM_REAL) (k[2] * k[2] * v + c);
01230 }
01231 
01232 /*-------------------------------------------------------------------*/
01233 /* conversion d'une matrice de rotation en vecteur de rotation          */
01234 /* en passant par un quaternion (source toolkit matrix_h.c)             */
01235 
01236 void    mr3d_to_axis_angle(VT3D axis, const MR3D mr)
01237 
01238 { MatriX     matrix;
01239   VT3D       vt_zero = { 0., 0., 0. };
01240   QUATERNION quat;
01241   double     angle, scalar, norm;
01242 
01243   matrix_compose (mr, vt_zero, matrix);
01244 
01245   quat_from_matrix (matrix, quat);
01246 
01247    /* calculate angle */
01248    angle = 2.0 * safe_acos(quat[3]);
01249 
01250    norm = sqrt(quat[0]*quat[0] + quat[1]*quat[1] + quat[2]*quat[2]) ;
01251    if (norm > EPSILON)
01252       {
01253         scalar  = angle/norm ;
01254         axis[0] = (LIBGEOM_REAL) (scalar * quat[0]);
01255         axis[1] = (LIBGEOM_REAL) (scalar * quat[1]);
01256         axis[2] = (LIBGEOM_REAL) (scalar * quat[2]);
01257       }
01258    else
01259       {
01260         axis[0] = (LIBGEOM_REAL) angle ;
01261         axis[1] = 0. ;
01262         axis[2] = 0. ;
01263       }
01264 }
01265 
01266 /*-------------------------------------------------------------------*/
01267 /* renvoie seulement la valeur de l'axis-angle de la matrice  mr     */
01268 /* cette valeur est toujours positive comprise dans [0,pi]           */
01269 /* d'apres Graphic Gems I, p466 */
01270 
01271 double  mr3d_axis_angle(const MR3D mr)
01272 {
01273    double ww;
01274 
01275    ww = (mr[0][0] + mr[1][1] + mr[2][2] -1.)/2. ;
01276    return safe_acos(ww);
01277 }
01278 
01279 /*-------------------------------------------------------------------*/
01280 bool mr3d_egalite(const MR3D    a,
01281                   const MR3D    b, 
01282                   LIBGEOM_REAL  seuil_mr)
01283 {
01284         LIBGEOM_REAL    delta;
01285         int     i,j,egalite;
01286 
01287         for(egalite=1,i=0 ; i<3 ; i++)
01288         {
01289           for(j=0 ; j<3 ; j++)
01290           {
01291             delta = fabs(a[i][j]-b[i][j]) ;
01292             if(delta > seuil_mr)
01293             {
01294               if(DEBUG_GEOM)
01295               {
01296                 printf(" warning : 3x3 matrice difference of %f \n", delta);
01297                 printf("           for element [%d][%d]\n", i, j);
01298               }
01299               egalite = 0;
01300             }
01301           }
01302         }
01303         return(egalite);
01304 }
01305 
01306 /*-------------------------------------------------------------------*/
01307 /* Cette procedure cherche a attirer une matrice vers l'identite.   */
01308 /* si l'ecart entre l'un de ses elements et la valeur correspondante*/
01309 /* de l'identite est inferieur a un seuil alors l'element la prend. */
01310 
01311 
01312 int     mr3d_attraction_idt(MR3D        a, 
01313                             LIBGEOM_REAL        seuil_mr)
01314 {
01315         int     i,j,k ;
01316 
01317         k = 0 ;
01318 
01319         for(i=0 ; i<3 ; i++)
01320         {
01321           for(j=0 ; j<3 ; j++)
01322           {
01323             if(i!=j)
01324               if(fabs((double)a[i][j]) < seuil_mr) 
01325                 {a[i][j] = 0. ; k++ ; }
01326             else
01327               if(fabs((double)(a[i][j] - 1.)) < seuil_mr)
01328                 {a[i][j] = 1. ; k++ ; }
01329           }
01330         }
01331 
01332         if(k == 0)         return(ATTRACTION_NULLE);
01333         else if(k == 9)    return(ATTRACTION_COMPLETE);
01334         else               return(ATTRACTION_PARTIELLE);
01335 }
01336 
01337 /*-------------------------------------------------------------------*/
01338 /* Cette procedure cherche a attirer une matrice vers une combinaison   */
01339 /* de vecteurs formes de 0. et de 1. si la difference est inferieure a  */
01340 /* la valeur de seuil donnee en parametre. Aucune verification de       */
01341 /* normalisation du resultat n'est effectuee.                           */
01342 
01343 int     mr3d_attraction_ini(MR3D        a, 
01344                             LIBGEOM_REAL        seuil_mr)
01345 {
01346         int     i,j,k ;
01347 
01348         k = 0 ;
01349 
01350         for(i=0 ; i<3 ; i++)
01351         {
01352           for(j=0 ; j<3 ; j++)
01353           {
01354             if(fabs((double)a[i][j]) < seuil_mr) 
01355               {a[i][j] = 0. ; k++ ; }
01356             else if(fabs((double)(a[i][j] - 1.)) < seuil_mr)
01357               {a[i][j] = 1. ; k++ ; }
01358           }
01359         }
01360 
01361         if(k == 0)         return(ATTRACTION_NULLE);
01362         else if(k == 9)    return(ATTRACTION_COMPLETE);
01363         else               return(ATTRACTION_PARTIELLE);
01364 }
01365 
01366 /*-------------------------------------------------------------------*/
01367 /*-------------------------------------------------------------------*/
01368 /*-------------------------------------------------------------------*/
01369 /* conversion de la matrice ligne m en trois angles XYZ mobile          */
01370 /* ang1 et ang3 sont normalises entre + ou - PI, ang2 entre + ou - PI/2 */
01371 
01372 void mr3d_conv_xyz_mob (const MR3D m, LIBGEOM_REAL *ang1,LIBGEOM_REAL *ang2,LIBGEOM_REAL *ang3)
01373 {
01374    LIBGEOM_REAL  a1,a2,a3;
01375    double Epsilon = 0.001;
01376 
01377    /* This is based on the equations found in "Introduction
01378       to robotics", by J.Craig, p. 47
01379 
01380       alpha = a3
01381       beta  = a2
01382       gamma = a1
01383 
01384     */
01385 
01386    a2 = atan2 (-m[2][0], sqrt (m[0][0]*m[0][0] + m[1][0]*m[1][0]));
01387 
01388    if (fabs(a2 - M_PI_2) < Epsilon) {  
01389       a1 = atan2 (m[0][1], m[1][1]);
01390       a3 = 0.;
01391    } else
01392    if (fabs(a2 + M_PI_2) < Epsilon) { 
01393       a1 = -atan2 (m[0][1], m[1][1]);
01394       a3 = 0.;
01395    } else {
01396       a1 = atan2 (m[2][1], m[2][2]);
01397       a3 = atan2 (m[1][0], m[0][0]);
01398    }
01399 
01400    /* A sign inversion to be compatible with the inverse function... */
01401 
01402    *ang1 = -a1;
01403    *ang2 = -a2;
01404    *ang3 = -a3;
01405 }
01406 
01407 /*------------------------------------------------------------------*/
01408 /* conversion de la matrice ligne m en trois angles YXZ mobile      */
01409 /* ang1 et ang3 sont normalises entre + ou - PI, ang2 entre +- PI/2 */
01410 /* correspond a la sequence pour l'analyse des mvts en orthopedie   */
01411 
01412 void  mr3d_conv_yxz_mob (const MR3D m, LIBGEOM_REAL *ang1, LIBGEOM_REAL *ang2, LIBGEOM_REAL *ang3)
01413 {
01414   LIBGEOM_REAL  a1,a2,a3;
01415   double Epsilon = 0.001;
01416 
01417   /* Derived like the _xyz version (see Craig). */
01418 
01419   a2 = atan2 (m [2][1], sqrt (m [1][1] * m [1][1] + m [0][1] * m [0][1]));
01420 
01421   if (fabs (a2 - M_PI_2) < Epsilon)
01422   { a1 = atan2 (m [1][0], m [0][0]);
01423     a3 = 0.;
01424   }
01425   else
01426   if (fabs (a2 + M_PI_2) < Epsilon)
01427   { a1 = -atan2 (m [1][0], m [0][0]);
01428     a3 = 0.;
01429   }
01430   else
01431   { a1 = -atan2 (m [2][0], m [2][2]);
01432     a3 = -atan2 (m [0][1], m [1][1]);
01433   }
01434 
01435   /* A sign conversion to be compatible with the inverse function... */
01436 
01437   *ang1 = -a1;
01438   *ang2 = -a2;
01439   *ang3 = -a3;
01440 }
01441 
01442 /*@$-------------------------------------------------------------------
01443     Public  FUNCTION: 
01444     FUNCTIONALITY   : convert the matrix (line-matrix) in 3 angles ZXY.
01445     ang1 and ang3 normalised between +- PI, ang2 between +- PI/2.
01446     Correspond a la sequence pour l'analyse des mvts en homophobie 
01447     (Walter'93).
01448 
01449     Zinv(ang1) * Z_ON_Y * Zinv(ang2) * Z_ON_Y * Zinv(ang3)
01450 
01451     Remember that Z_ON_Y = inverse(Z_ON_X) !!!!!!
01452 
01453     KEYWORD(S)      : Sequence d'Euler-Boulic, dites de l'Euler-tronquee
01454     mieux connue sous le nom d'Euler-ouimaisnon.
01455     -------------------------------------------------------------------
01456     FUNCTION TYPE   : bool
01457     here parameter description with : flow / name / functionality  
01458     the flow can be one of  IN / OUT / IO (for IN and OUT)
01459     ---------------------------------------------------------------$@*/
01460 void mr3d_conv_EulerBoulic_zxy(MR3D_t m, LIBGEOM_REAL *ang1, LIBGEOM_REAL *ang2, LIBGEOM_REAL *ang3,
01461                                bool verbose)
01462 {
01463     double a1,a2,a3, s2;
01464     double Epsilon = 0.001;
01465 
01466     s2 = (double)  m[2][2] ;  
01467     a2 = asin(s2);
01468 
01469       if (fabs(a2 - M_PI_2) < Epsilon)  /* singularite  a2 == pi/2  */
01470       {
01471           if(verbose) 
01472             fprintf(stderr,"Warning: Euler-Boulic Singularity (PI/2) in ZXY\n");
01473           a1 = atan2((double) (m[1][1]), (double)(m[0][1]));
01474           a2 = M_PI_2;
01475           a3 = 0.0;
01476       }
01477       else if (fabs(a2 + M_PI_2) < Epsilon) /* singularite a2==-pi/2 */
01478       { 
01479           if(verbose) 
01480             fprintf(stderr,"Warning: Euler-Boulic Singularity (-PI/2) in ZXY\n");
01481           a1 = atan2((double) (m[1][1]), (double)(m[0][1]));
01482           a2 = -M_PI_2;
01483           a3 = 0.0;
01484       }
01485       else
01486       {
01487         a1 = atan2((double)(-m[0][2]), (double)(m[1][2]));        
01488         a3 = atan2((double)(-m[2][1]), (double)(m[2][0]));
01489       }
01490 
01491    *ang1 = (LIBGEOM_REAL)a1;
01492    *ang2 = (LIBGEOM_REAL)a2;
01493    *ang3 = (LIBGEOM_REAL)a3;
01494 }
01495 
01496 /*@$-------------------------------------------------------------------
01497     Public  FUNCTION: 
01498     FUNCTIONALITY   : convert the matrix (line-matrix) in 3 angles ZYX.
01499     ang1 and ang3 normalised between +- PI, ang2 between +- PI/2.
01500     Correspond a la sequence pour l'analyse des mvts en homophobie 
01501     (Walter'93).
01502 
01503     Zinv(ang1) * Z_ON_X * Zinv(ang2) * Z_ON_X * Zinv(ang3)
01504 
01505     Remember that Z_ON_X = inverse(Z_ON_Y) !!!!!!
01506 
01507     KEYWORD(S)      : Sequence d'Euler-Boulic, dites de l'Euler-tronquee
01508     mieux connue sous le nom d'Euler-ouimaisnon.
01509     -------------------------------------------------------------------
01510     FUNCTION TYPE   : bool
01511     here parameter description with : flow / name / functionality  
01512     the flow can be one of  IN / OUT / IO (for IN and OUT)
01513     ---------------------------------------------------------------$@*/
01514 void  mr3d_conv_EulerBoulic_zyx(MR3D_t m, LIBGEOM_REAL *ang1, LIBGEOM_REAL *ang2, 
01515                                 LIBGEOM_REAL *ang3, bool verbose)
01516 {
01517     double a1,a2,a3, s2;
01518     double Epsilon = 0.001;
01519 
01520     s2 = (double) -m[2][2] ;  
01521     a2 = asin(s2);
01522 
01523     if (fabs(a2 - M_PI_2) < Epsilon)  /* singularite  a2 == pi/2  */
01524     {
01525         if(verbose) 
01526             fprintf(stderr,"Warning: Euler-Boulic Singularity (PI/2) in ZYX\n");
01527         a1 = atan2((double)(-m[0][0]), (double)(m[1][0]));
01528         a2 = M_PI_2;
01529         a3 = 0.0;
01530     }
01531     else if (fabs(a2 + M_PI_2) < Epsilon) /* singularite a2==-pi/2 */
01532     { 
01533         if(verbose) 
01534             fprintf(stderr,"Warning: Euler-Boulic Singularity (-PI/2) in ZYX\n");
01535         a1 = atan2((double)(-m[0][0]), (double)(m[1][0]));
01536         a2 = -M_PI_2;
01537         a3 = 0.0;
01538     }
01539     else
01540     {
01541         a1 = atan2((double)(m[1][2]), (double)(m[0][2]));
01542         a3 = atan2((double)(m[2][0]), (double)(m[2][1]));
01543     }
01544 
01545     *ang1 = (LIBGEOM_REAL)a1;
01546     *ang2 = (LIBGEOM_REAL)a2;
01547     *ang3 = (LIBGEOM_REAL)a3;
01548 }
01549 
01550 /*@$-------------------------------------------------------------------
01551     Public  FUNCTION: 
01552     FUNCTIONALITY   : convert the matrix (line-matrix) in 2 angles ZX.
01553     ang1 and ang2 normalised between +- PI.
01554     Correspond a la sequence pour l'analyse des mvts en homophobie 
01555     (Walter'93).
01556     KEYWORD(S)      : Sequence d'Euler-Boulic-2D, dites de 
01557     l'Euler-doublement-tronquee mieux connue sous le nom 
01558     d'Euler-ouimaisnonmaisnon.
01559     -------------------------------------------------------------------
01560     FUNCTION TYPE   : bool
01561     here parameter description with : flow / name / functionality  
01562     the flow can be one of  IN / OUT / IO (for IN and OUT)
01563     ---------------------------------------------------------------$@*/
01564 void  mr3d_conv_EulerBoulic_zx(MR3D_t m, LIBGEOM_REAL *ang1, LIBGEOM_REAL *ang2, 
01565                        bool verbose)
01566 {
01567    *ang1 = (LIBGEOM_REAL) atan2((double)( m[1][2]), (double)(m[0][2]));
01568    *ang2 = (LIBGEOM_REAL) atan2((double)( m[2][0]), (double)(m[2][1]));
01569 }
01570 
01571 /*@$-------------------------------------------------------------------
01572     Public  FUNCTION: 
01573     FUNCTIONALITY   : convert the matrix (line-matrix) in 2 angles ZY.
01574     ang1 and ang2 normalised between +- PI.
01575     Correspond a la sequence pour l'analyse des mvts en homophobie 
01576     (Walter'93).
01577     KEYWORD(S)      : Sequence d'Euler-Boulic-2D, dites de 
01578     l'Euler-doublement-tronquee mieux connue sous le nom 
01579     d'Euler-ouimaisnonmaisnon.
01580     -------------------------------------------------------------------
01581     FUNCTION TYPE   : bool
01582     here parameter description with : flow / name / functionality  
01583     the flow can be one of  IN / OUT / IO (for IN and OUT)
01584     ---------------------------------------------------------------$@*/
01585 void  mr3d_conv_EulerBoulic_zy(MR3D_t m, LIBGEOM_REAL *ang1, LIBGEOM_REAL *ang2,
01586                               bool verbose)
01587 {
01588    *ang1 = (LIBGEOM_REAL) atan2((double)(-m[0][2]), (double)(m[1][2]));
01589    *ang2 = (LIBGEOM_REAL) atan2((double)(-m[2][1]), (double)(m[2][0]));
01590 }
01591 
01592 /*@$-------------------------------------------------------------------
01593     Public  FUNCTION: 
01594     FUNCTIONALITY   : convert the matrix (line-matrix) in 1 angles Z.
01595     ang1 normalised between +- PI.
01596     Correspond a la sequence pour l'analyse des mvts en homophobie 
01597     (Walter'93).
01598     KEYWORD(S)      : Sequence d'Euler-Boulic-1D, dites de 
01599     l'Euler-triplement-tronquee mieux connue sous le nom 
01600     d'Euler-ouimaisnonmaisnonmaisnon.
01601     -------------------------------------------------------------------
01602     FUNCTION TYPE   : bool
01603     here parameter description with : flow / name / functionality  
01604     the flow can be one of  IN / OUT / IO (for IN and OUT)
01605     ---------------------------------------------------------------$@*/
01606 void  mr3d_conv_EulerBoulic_z(MR3D_t m, LIBGEOM_REAL *ang1, bool verbose)
01607 {
01608    *ang1 = (LIBGEOM_REAL) atan2((double)( m[1][0]), (double)(m[0][0]));
01609 }
01610 
01611 /*-------------------------------------------------------------------*/
01612 
01613 void mr3d_from_angle_seq_xyz(MR3D mx,LIBGEOM_REAL angX, LIBGEOM_REAL angY, LIBGEOM_REAL angZ)
01614      /* From a rotation angle sequence to a rotation matrix.
01615         Taken from Graphics Gems IV p. 222, but adpated to 
01616         produce a row(!) matrix. It replaces the GL code:
01617           irisGL_loadmatrix(idt);
01618           irisGL_rot(angleX, 'x');
01619           irisGL_rot(angleY, 'y');
01620           irisGL_rot(angleZ, 'z');
01621           irisGL_getmatrix(newMx); 
01622         angle order: XYZr = [Z,Odd,Diff,R-frame] */
01623 {
01624     LIBGEOM_REAL ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
01625    
01626     ci = cos(-angZ);
01627     cj = cos(-angY); 
01628     ch = cos(-angX);
01629     si = sin(-angZ);
01630     sj = sin(-angY); 
01631     sh = sin(-angX);
01632     cc = ci*ch; 
01633     cs = ci*sh; 
01634     sc = si*ch; 
01635     ss = si*sh;
01636     
01637     mx[0][0] = cj*ci;    mx[1][0] = cj*si;    mx[2][0] = -sj;      
01638     mx[0][1] = sj*cs-sc; mx[1][1] = sj*ss+cc; mx[2][1] = cj*sh; 
01639     mx[0][2] = sj*cc+ss; mx[1][2] = sj*sc-cs; mx[2][2] = cj*ch;
01640 }
01641 
01642 /*-------------------------------------------------------------------*/
01643 
01644 void mr3d_from_angle_seq_yxz(MR3D mx, LIBGEOM_REAL angY, LIBGEOM_REAL angX, LIBGEOM_REAL angZ)
01645      /* From a rotation angle sequence to a rotation matrix.
01646         Taken from Graphics Gems IV p. 222, but adpated to 
01647         produce a row(!) matrix. It replaces the GL code:
01648           irisGL_loadmatrix(idt);
01649           irisGL_rot(angleX, 'y');
01650           irisGL_rot(angleY, 'x');
01651           irisGL_rot(angleZ, 'z');
01652           irisGL_getmatrix(newMx); 
01653         angle order: YXZr = [Z,Even,Diff,R-frame] */
01654 {
01655   LIBGEOM_REAL ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
01656   
01657   ci = cos(angZ);
01658   cj = cos(angX); 
01659   ch = cos(angY);
01660   si = sin(angZ);
01661   sj = sin(angX); 
01662   sh = sin(angY);
01663   cc = ci*ch;   
01664   cs = ci*sh;   
01665   sc = si*ch;  
01666   ss = si*sh;
01667      
01668   mx[0][0] = sj*ss+cc; mx[1][0] = sj*cs-sc; mx[2][0] = cj*sh; 
01669   mx[0][1] = cj*si;    mx[1][1] = cj*ci;    mx[2][1] = -sj;   
01670   mx[0][2] = sj*sc-cs; mx[1][2] = sj*cc+ss; mx[2][2] = cj*ch; 
01671 }
01672 
01673 
01677 void mr3d_from_two_vectors(const VT3D_t a, const VT3D_t b, MR3D R)
01678 {
01679    static VT3D v0, v1, absv0, leastCoordAxis, axis;
01680    LIBGEOM_REAL cosTheta, sinTheta, x, y, z, t;
01681 
01682    vt3d_normalize(a, v0);
01683    vt3d_normalize(b, v1);
01684 
01685    cosTheta = vt3d_get_dot(v0, v1);
01686    vt3d_cross(v0, v1, axis);
01687    sinTheta = vt3d_get_norm(axis);
01688     
01689    if (fabs(sinTheta) > EPSIL_BIG_ZERO)
01690    {
01691       /* normalize axis */
01692       axis[0] /= sinTheta;
01693       axis[1] /= sinTheta;
01694       axis[2] /= sinTheta;
01695    }
01696    else if (cosTheta < 0.0)  /* singular case, vectors are colinear but opposite */
01697    {
01698       absv0[0] = fabs(v0[0]); absv0[1] = fabs(v0[1]); absv0[2] = fabs(v0[2]);
01699       leastCoordAxis[0] = leastCoordAxis[1] = leastCoordAxis[2] = 0;
01700       leastCoordAxis[absv0[0]<=absv0[1] ? absv0[0]<=absv0[2] ? 0 : 2
01701                     : absv0[1]<=absv0[2] ? 1 : 2] = 1;
01702       vt3d_cross(v0, leastCoordAxis, axis);
01703       vt3d_normalize(axis, axis);
01704    }
01705    else
01706    {
01707       mr3d_idt_(R);
01708       return;
01709    }
01710     
01711    x = axis[0];
01712    y = axis[1];
01713    z = axis[2];
01714     
01715    t = 1.0f - cosTheta;
01716     
01717    R[0][0] = t * x * x + cosTheta;
01718    R[0][1] = t * x * y + sinTheta * z;
01719    R[0][2] = t * x * z - sinTheta * y;
01720    R[1][0] = t * y * x - sinTheta * z;
01721    R[1][1] = t * y * y + cosTheta;
01722    R[1][2] = t * y * z + sinTheta * x;
01723    R[2][0] = t * z * x + sinTheta * y;
01724    R[2][1] = t * z * y - sinTheta * x;
01725    R[2][2] = t * z * z + cosTheta;
01726 } 
01727 
01728 /*@#-------------------------------------------------------------------
01729     Public FUNCTION : 
01730     FUNCTIONALITY   : re-orthogonalization of matrix
01731     KEYWORD(S)      : 
01732     -------------------------------------------------------------------
01733     FUNCTION TYPE   : void
01734     here parameter description with : flow / name / functionality  
01735     the flow can be one of  IN / OUT / IO (for IN and OUT)
01736     ---------------------------------------------------------------#@*/
01737 /* 
01738    MatriX Orthogonalization
01739    Eric Raible
01740    from "Graphics Gems", Academic Press, 1990
01741 
01742    Modified 09/11/93 by Tom Molet for MR3D compatibility,
01743    and ANSI-C conversion.
01744 */
01745 
01746 /* find maximum of a and b */
01747 #define MAX(a,b)        (((a)>(b))?(a):(b))     
01748 
01749 /*
01750  * Reorthogonalize matrix R - that is find an orthogonal matrix that is
01751  * "close" to R by computing an approximation to the orthogonal matrix
01752  *
01753  *           T  -1/2
01754  *   RC = R(R R)
01755  *                              T      -1
01756  * [RC is orthogonal because (RC) = (RC) ]
01757  *                                                                -1/2
01758  * To compute C, we evaluate the Taylor expansion of F(x) = (I + x)
01759  * (where x = C - I) about x=0.
01760  * This gives C = I - (1/2)x + (3/8)x^2 - (5/16)x^3 + ...
01761  */
01762 
01763 static LIBGEOM_REAL coef[10] =                  /* From mathematica */
01764   { 1., -1./2., 3./8., -5./16., 35./128., -63./256.,
01765     231./1024., -429./2048., 6435./32768., -12155./65536. };
01766 
01767 void    mr3d_reorthogonalize (MR3D R, int limit)
01768 {
01769   MR3D I, Temp, X, X_power, Sum;
01770   int power;
01771 
01772   limit = MAX(limit, 10);
01773 
01774   mr3d_transpose (R, Temp);             /* Rt */
01775   mr3d_mult (Temp, R, Temp);    /* RtR */
01776   mr3d_idt_ (I);
01777   mr3d_sub (Temp, I, X);        /* RtR - I */
01778   mr3d_idt_ (X_power);          /* X^0 */
01779   mr3d_idt_ (Sum);                      /* coef[0] * X^0 */
01780 
01781   for (power = 1; power < limit; ++power)
01782     {
01783       mr3d_mult (X_power, X, X_power);
01784       mr3d_scale (X_power, coef[power], Temp);
01785       mr3d_add (Sum, Temp, Sum);
01786     }
01787 
01788   mr3d_mult (R, Sum, R);
01789 }
01790 
01791 
01792 /*@#-------------------------------------------------------------------
01793     Public FUNCTION : 
01794     FUNCTIONALITY   : write the rotation-matrix self in the file f.
01795     KEYWORD(S)      : 
01796     -------------------------------------------------------------------
01797     FUNCTION TYPE   : bool
01798     here parameter description with : flow / name / functionality  
01799     the flow can be one of  IN / OUT / IO (for IN and OUT)
01800     ---------------------------------------------------------------#@*/
01801 bool    mr3d_write(const MR3D self, FILE * f)
01802 {
01803   char *format_str;
01804 
01805   if (sizeof(LIBGEOM_REAL) == sizeof(float))
01806     format_str = "%f %f %f\n";
01807   else 
01808     format_str = "%lf %lf %lf\n";
01809 
01810     if(f)
01811     {
01812         fprintf(f, format_str,self[GEOM_X_INDEX][GEOM_X_INDEX], 
01813                                 self[GEOM_X_INDEX][GEOM_Y_INDEX], 
01814                                 self[GEOM_X_INDEX][GEOM_Z_INDEX]);
01815         
01816         fprintf(f, format_str,self[GEOM_Y_INDEX][GEOM_X_INDEX], 
01817                                 self[GEOM_Y_INDEX][GEOM_Y_INDEX], 
01818                                 self[GEOM_Y_INDEX][GEOM_Z_INDEX]);
01819         
01820         fprintf(f, format_str,self[GEOM_Z_INDEX][GEOM_X_INDEX], 
01821                                 self[GEOM_Z_INDEX][GEOM_Y_INDEX], 
01822                                 self[GEOM_Z_INDEX][GEOM_Z_INDEX]);
01823         
01824         return(true);
01825     }
01826     return(false);
01827 }
01828 
01829 
01830 /*@#-------------------------------------------------------------------
01831     Public FUNCTION : 
01832     FUNCTIONALITY   : read the rotation-matrix self from the file f.
01833     KEYWORD(S)      : 
01834     -------------------------------------------------------------------
01835     FUNCTION TYPE   : bool
01836     here parameter description with : flow / name / functionality  
01837     the flow can be one of  IN / OUT / IO (for IN and OUT)
01838     ---------------------------------------------------------------#@*/
01839 bool    mr3d_read(MR3D self, FILE * f)
01840 {
01841   char *format_str;
01842 
01843   if (sizeof(LIBGEOM_REAL) == sizeof(float))
01844     format_str = "%f %f %f";
01845   else 
01846     format_str = "%lf %lf %lf";
01847 
01848     if(f)
01849     {
01850         fscanf(f, format_str,&self[GEOM_X_INDEX][GEOM_X_INDEX], 
01851                                 &self[GEOM_X_INDEX][GEOM_Y_INDEX], 
01852                                 &self[GEOM_X_INDEX][GEOM_Z_INDEX]);
01853         
01854          
01855         fscanf(f, format_str,&self[GEOM_Y_INDEX][GEOM_X_INDEX], 
01856                                 &self[GEOM_Y_INDEX][GEOM_Y_INDEX], 
01857                                 &self[GEOM_Y_INDEX][GEOM_Z_INDEX]);
01858         
01859          
01860         fscanf(f, format_str,&self[GEOM_Z_INDEX][GEOM_X_INDEX], 
01861                                 &self[GEOM_Z_INDEX][GEOM_Y_INDEX], 
01862                                 &self[GEOM_Z_INDEX][GEOM_Z_INDEX]);
01863         
01864          
01865         return(true);
01866     }
01867     return(false);
01868 }
01869 
01870 
01871 
01872 /*-------------------------------------------------------------------*/
01873 /*-------------------------------------------------------------------*/
01874 /*-------------------------------------------------------------------*/
01875 
01876 void    vt3d_get(const MatriX       matrix,
01877                  VT3D       v)
01878 {
01879         v[0] = matrix[3][0] ;
01880         v[1] = matrix[3][1] ;
01881         v[2] = matrix[3][2] ;
01882 }
01883 
01884 /*-------------------------------------------------------------------*/
01885 
01886 void    vt3d_load(MatriX    matrix,
01887                   const VT3D        v)
01888 {
01889         matrix[3][0] = v[0] ;
01890         matrix[3][1] = v[1] ;
01891         matrix[3][2] = v[2] ;
01892 }
01893 
01894 /*-------------------------------------------------------------------*/
01895 /* Transcription d'un vecteur 3d sous forme d'un vecteur 4d pour de     */
01896 /* futures manipulations par des transformations homogenes (sans zoom)  */
01897  
01898 void    vt3d_vhom(const VT3D        vt3d, 
01899                   VHOM      vhom)
01900 {
01901         vhom[0] = vt3d[0];
01902         vhom[1] = vt3d[1];
01903         vhom[2] = vt3d[2];
01904         vhom[3] = 1. ;
01905 }
01906 
01907 /*-------------------------------------------------------------------*/
01908 /* Transcription d'un vecteur 4d homogene en vecteur 3d (hyp : zoom=1)  */
01909 
01910 void    vhom_vt3d(const VHOM        vhom, 
01911                   VT3D      vt3d)
01912 {
01913         vt3d[0] = vhom[0];
01914         vt3d[1] = vhom[1];
01915         vt3d[2] = vhom[2];
01916 }
01917 
01918 /*-------------------------------------------------------------------*/
01919 /* LET: affectation d'un vecteur.       (assignment)                    */
01920 
01921 void    vt3d_let(LIBGEOM_REAL x, LIBGEOM_REAL y, LIBGEOM_REAL z, VT3D w)
01922 {
01923    w[0] = x;
01924    w[1] = y;
01925    w[2] = z;
01926 }
01927 
01928 /*@#-------------------------------------------------------------------
01929     Public FUNCTION : 
01930     FUNCTIONALITY   : 
01931     KEYWORD(S)      : 
01932     -------------------------------------------------------------------
01933     FUNCTION TYPE   : void
01934     here parameter description with : flow / name / functionality  
01935     the flow can be one of  IN / OUT / IO (for IN and OUT)
01936     ---------------------------------------------------------------#@*/
01937 void    vt3d_copy(const VT3D src, VT3D dst)
01938 {
01939     dst[0] = src[0];
01940     dst[1] = src[1];
01941     dst[2] = src[2];
01942 }
01943 
01944 /*@#-------------------------------------------------------------------
01945     Public FUNCTION : 
01946     FUNCTIONALITY   : 
01947     KEYWORD(S)      : 
01948     -------------------------------------------------------------------
01949     FUNCTION TYPE   : void
01950     here parameter description with : flow / name / functionality  
01951     the flow can be one of  IN / OUT / IO (for IN and OUT)
01952     ---------------------------------------------------------------#@*/
01953 void    vt3d_set_null(VT3D dst)
01954 {
01955     dst[0] = 0.0;
01956     dst[1] = 0.0;
01957     dst[2] = 0.0;
01958 }
01959 
01960 /*-------------------------------------------------------------------*/
01961 /* ADD: u + v.                                                          */
01962 
01963 void    vt3d_add(const VT3D u, const VT3D v,VT3D w)
01964 {
01965    w[0] = u[0] + v[0];
01966    w[1] = u[1] + v[1];
01967    w[2] = u[2] + v[2];
01968 }
01969 
01970 /*-------------------------------------------------------------------*/
01971 /* SOUST: u - v.                                                        */
01972 
01973 void    vt3d_sub(const VT3D u, const VT3D v,VT3D w)
01974 {
01975    w[0] = u[0] - v[0];
01976    w[1] = u[1] - v[1];
01977    w[2] = u[2] - v[2];
01978 }
01979 
01980 /*-------------------------------------------------------------------*/
01981 /* MULT: retourne le resultat de la multiplication de u avec v.         */
01982 /* same as scale */
01983 
01984 void    vt3d_mult(const VT3D u, const VT3D v,VT3D w)
01985 {
01986    w[0] = u[0] * v[0];
01987    w[1] = u[1] * v[1];
01988    w[2] = u[2] * v[2];
01989 }
01990 
01991 /*-------------------------------------------------------------------*/
01992 /* DIV: retourne le resultat de la division de u avec v.                */
01993 
01994 void    vt3d_div(const VT3D u, const VT3D v,VT3D w)
01995 {
01996    w[0] = u[0] / v[0];
01997    w[1] = u[1] / v[1];
01998    w[2] = u[2] / v[2];
01999 }
02000 
02001 /*-------------------------------------------------------------------*/
02002 /* MULTV: multiplication d'un vecteur avec un scalaire.                 */
02003 
02004 void    vt3d_mults(const VT3D v,LIBGEOM_REAL s, VT3D w)
02005 {
02006    w[0] = v[0] * s;
02007    w[1] = v[1] * s;
02008    w[2] = v[2] * s;
02009 }
02010 
02011 /*-------------------------------------------------------------------*/
02012 /* DIVS: division d'un vecteur avec un scalaire.                        */
02013 
02014 void    vt3d_divs(const VT3D v,LIBGEOM_REAL s, VT3D w)
02015 {
02016    if (s != 0.0) {
02017       w[0] = v[0] / s;
02018       w[1] = v[1] / s;
02019       w[2] = v[2] / s;
02020    }
02021 }
02022 
02023 /*-------------------------------------------------------------------*/
02024 /* negate a vt3d vector (change sign).                               */
02025 
02026 void vt3d_neg (const VT3D src, VT3D dest)
02027 
02028 { dest [0] = - src [0];
02029   dest [1] = - src [1];
02030   dest [2] = - src [2];
02031 }
02032 
02033 /*-------------------------------------------------------------------*/
02034 /* NORME: retourne la norme du vecteur v. (norm)                        */
02035 
02036 LIBGEOM_REAL    vt3d_get_norm(const VT3D v)
02037 {
02038    return( (LIBGEOM_REAL)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) );
02039 }
02040 
02041 /*-------------------------------------------------------------------*/
02042 /* NORME2: retourne la norme au carre du vecteur v.                     */
02043 
02044 LIBGEOM_REAL    vt3d_get_norm2(const VT3D v)
02045 {
02046    return( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] );
02047 }
02048 
02049 /*-------------------------------------------------------------------*/
02050 /* DIST: distance entre deux points.    (norm of u-v)                   */
02051 
02052 LIBGEOM_REAL    vt3d_get_dist(const VT3D u, const VT3D v)
02053 {
02054     VT3D    w;
02055 
02056     vt3d_sub(u,v,w);
02057     return(vt3d_get_norm(w));
02058 }
02059 
02060 /*-------------------------------------------------------------------*/
02061 /* DISTPTDROITE: distance entre un point P et la droite definie par un  */
02062 /*                 point Q et une direction unitaire N.                 */
02063 /*              (shortest dist between point and a line)                */
02064 
02065 LIBGEOM_REAL    vt3d_get_distptline(const VT3D p, const VT3D q, const VT3D n)
02066 {
02067     VT3D    w ;
02068 
02069     vt3d_sub(p, q, w);
02070     vt3d_cross(n,w, w);
02071     return(vt3d_get_norm(w));
02072 }
02073 
02074 /*-------------------------------------------------------------------*/
02075 /* DISTPTPLAN: distance entre un point P et le plan defini par un point */
02076 /*               Q et une normale unitaire N.                           */
02077 /*              (shortest dist between point and a plane)               */
02078 
02079 LIBGEOM_REAL    vt3d_get_distptplane(const VT3D p, const VT3D q, const VT3D n)
02080 {
02081     VT3D    w ;
02082 
02083     vt3d_sub(p, q, w);
02084     return((LIBGEOM_REAL)fabs((double)vt3d_get_dot(n,w)));
02085 }
02086 
02087 /*-------------------------------------------------------------------*/
02088 /* ROTV: rotation du vecteur V autour de l'axe K (x,y ou z) de A radian.*/
02089 /*         SA et CA sont les sinus et cosinus de A.                     */
02090 /*      (rotate v around x or y or z by angle  A rd)                    */
02091 
02092 void    vt3d_rotv(const VT3D v,LIBGEOM_REAL sa, LIBGEOM_REAL ca, char k, VT3D w)
02093 {
02094    switch(k) {
02095       case 'x':
02096          vt3d_let(v[0], v[1]*ca-v[2]*sa, v[1]*sa+v[2]*ca, w);
02097          break;
02098       case 'y':
02099          vt3d_let(v[0]*ca+v[2]*sa, v[1], -v[0]*sa+v[2]*ca, w);
02100          break;
02101       case 'z':
02102          vt3d_let(v[0]*ca-v[1]*sa, v[0]*sa+v[1]*ca, v[2], w);
02103          break;
02104    }
02105 }
02106 
02107 /*-------------------------------------------------------------------*/
02108 /* ROTVECT: rotation du vecteur V autour de l'axe de centre C et de     */
02109 /*            direction K (unitaire) d'un angle A (radian).             */
02110 /*            SA et CA sont les sinus et cosinus de A.                  */
02111 /*      (rotate v around k passing by point c by angle  A rd)           */
02112 
02113 void    vt3d_rotvect(const VT3D v, const VT3D c, VT3D k, LIBGEOM_REAL sa, LIBGEOM_REAL ca, VT3D w)
02114 {
02115    LIBGEOM_REAL va,kxy,kxz,kyz;
02116    VT3D r1,r2,r3;
02117 
02118    va = 1.0 - ca;
02119    vt3d_sub(v,c,w);
02120 
02121    kxy = k[0] * k[1];
02122    kxz = k[0] * k[2];
02123    kyz = k[1] * k[2];
02124 
02125    vt3d_let( k[0]*k[0]*va+ca, kxy*va-k[2]*sa, kxz*va+k[1]*sa, r1 );
02126    vt3d_let( kxy*va+k[2]*sa, k[1]*k[1]*va+ca, kyz*va-k[0]*sa, r2 );
02127    vt3d_let( kxz*va-k[1]*sa, kyz*va+k[0]*sa, k[2]*k[2]*va+ca, r3 );
02128 
02129    vt3d_let(vt3d_get_dot(r1,w), vt3d_get_dot(r2,w), vt3d_get_dot(r3,w), w);
02130 
02131    vt3d_add(w,c,w);
02132 }
02133 
02134 /*-------------------------------------------------------------------*/
02135 /* construit dans v la normalisation du vecteur u                       */
02136 
02137 bool    vt3d_normalize(const VT3D       u,
02138                        VT3D     v)
02139 {
02140         double  norm ;
02141         int     i ;
02142 
02143         norm = sqrt((double)(u[0]*u[0] + u[1]*u[1] + u[2]*u[2])) ;
02144 
02145         if(norm > EPSIL_ZERO)
02146           {for(i=0 ; i<3 ; i++) v[i] = u[i]/norm ; return(true) ;}
02147         else
02148           {for(i=0 ; i<3 ; i++) v[i] = 0. ; return(false) ;}
02149 }
02150 
02151 /*-------------------------------------------------------------------*/
02152 /* calcule  le produit vectoriel u * v -> w (cross product)             */
02153 
02154 void    vt3d_cross(const VT3D   u,
02155                    const VT3D   v,
02156                    VT3D w)
02157 {
02158         VT3D    x;
02159 
02160         x[0] =   u[1]*v[2] - u[2]*v[1] ;
02161         x[1] = - u[0]*v[2] + u[2]*v[0] ;
02162         x[2] =   u[0]*v[1] - u[1]*v[0] ;
02163 
02164         w[0] = x[0] ; w[1] = x[1] ; w[2] = x[2] ;
02165 }
02166 
02167 /*-------------------------------------------------------------------*/
02168 /* applique un facteur d'echelle independant pour chaque coordonnee     */
02169 
02170 void    vt3d_scale(const VT3D       scale,
02171                    const VT3D       u,
02172                    VT3D     v)
02173 {
02174         v[0] =   u[0]*scale[0] ;
02175         v[1] =   u[1]*scale[1] ;
02176         v[2] =   u[2]*scale[2] ;
02177 }
02178 
02179 /*-------------------------------------------------------------------*/
02180 /* renvoie le produit scalaire u*v      (dot product)                   */
02181 
02182 LIBGEOM_REAL    vt3d_get_dot(const VT3D     u,
02183                      const VT3D     v)
02184 {
02185         return(u[0]*v[0] + u[1]*v[1] + u[2]*v[2]);
02186 }
02187 
02188 
02189 /*-------------------------------------------------------------------*/
02190 bool vt3d_egalite(const VT3D    a,
02191                   const VT3D    b, 
02192                   LIBGEOM_REAL  seuil_vt)
02193 {
02194         LIBGEOM_REAL    delta;
02195         int     i,egalite;
02196 
02197         for(egalite=1,i=0 ; i<3 ; i++)
02198         {
02199           delta = fabs(a[i]-b[i]) ;
02200           if(delta > seuil_vt)
02201           {
02202             if(DEBUG_GEOM)
02203             {
02204               printf(" warning : 3D vector difference of %f \n", delta);
02205               printf("           for element [%d]\n", i);
02206             }
02207             egalite = 0;
02208           }
02209         }
02210         return(egalite);
02211 }
02212 
02213 /*-------------------------------------------------------------------*/
02214 /* cette procedure attire un vecteur vers le vecteur nul. si un     */
02215 /* element est inferieur (en val abs) a un seuil il prend la valeur0*/
02216 
02217 int     vt3d_attraction_nul(VT3D        a, 
02218                             LIBGEOM_REAL        seuil_vt)
02219 {
02220         int     i,k;
02221 
02222         k = 0 ;
02223 
02224         for(i=0 ; i<3 ; i++)
02225           if(fabs((double)a[i]) < seuil_vt)
02226             {a[i] = 0. ; k++ ;}
02227 
02228         if(k == 0)         return(ATTRACTION_NULLE);
02229         else if(k == 3)    return(ATTRACTION_COMPLETE);
02230         else               return(ATTRACTION_PARTIELLE);
02231 }
02232 
02233 /*@#-------------------------------------------------------------------
02234     Public FUNCTION : 
02235     FUNCTIONALITY   : Tells if a point is inside a 2D polygon or not.
02236                       The polygon may be concave or convex, and is
02237                       made of N vertices pointed by p. Only the first
02238                       two coordinates are considered (x and y).
02239     KEYWORD(S)      : 
02240     -------------------------------------------------------------------
02241     FUNCTION TYPE   : bool
02242     here parameter description with : flow / name / functionality  
02243     the flow can be one of  IN / OUT / IO (for IN and OUT)
02244     ---------------------------------------------------------------#@*/
02245 
02246 bool vt3d_inside_polygon (VT3D point, VT3D *p, int N)
02247 
02248 {
02249   int     i, j;
02250   bool c = false;
02251   LIBGEOM_REAL   xt = point[0], yt = point[1];
02252 
02253   for (i = 0, j = N-1; i < N; j = i++)
02254   {
02255     if ((p[i][1]<=yt && yt<p[j][1] && (p[j][1]-p[i][1]) * (xt-p[i][0])<(p[j][0]-p[i][0])*(yt-p[i][1]))
02256         ||  (p[j][1]<=yt && yt<p[i][1] && (p[j][1]-p[i][1]) * (xt-p[i][0])>(p[j][0]-p[i][0])*(yt-p[i][1])))
02257     {
02258       c = !c;
02259     }
02260   }
02261 
02262   return c;
02263 }
02264 
02265 /*@#-------------------------------------------------------------------
02266     Public FUNCTION : 
02267     FUNCTIONALITY   : Rotates a vector about a given axis angle
02268                       (using Rodriguez formula).
02269     KEYWORD(S)      : 
02270     -------------------------------------------------------------------
02271     FUNCTION TYPE   : 
02272     here parameter description with : flow / name / functionality  
02273     the flow can be one of  IN / OUT / IO (for IN and OUT)
02274     ---------------------------------------------------------------#@*/
02275 
02276 void vt3d_rotate_around_axis_angle (const VT3D  axis_angle,
02277                                     const VT3D  v_in,
02278                                     VT3D  v_out)
02279 
02280 { LIBGEOM_REAL alpha = vt3d_get_norm (axis_angle);
02281 
02282   if (alpha > EPSILON)
02283   {
02284     LIBGEOM_REAL sin_alpha = sin (alpha),
02285           cos_alpha = cos (alpha);
02286     VT3D  v2, omega;
02287 
02288     vt3d_mults (axis_angle, 1./alpha, omega);
02289 
02290     vt3d_mults (v_in, cos_alpha, v_out);
02291     vt3d_cross (omega, v_in,     v2);
02292     vt3d_mults (v2, sin_alpha,   v2);
02293     vt3d_add   (v_out, v2, v_out);
02294 
02295     vt3d_mults (omega, vt3d_get_dot (omega, v_in) * (1. - cos_alpha), v2);
02296     vt3d_add   (v_out, v2, v_out);
02297   }
02298   else
02299   {
02300     vt3d_copy (v_in, v_out);
02301   }
02302 }
02303 
02304 /*---------------------------------------------------*/
02305 
02306 void vt3d_lerp (const VT3D p1, const VT3D p2, LIBGEOM_REAL u, VT3D result)
02307 
02308 { 
02309   static VT3D tmp;
02310 
02311   vt3d_mults (p1, 1-u, tmp);
02312   vt3d_mults (p2, u, result);
02313   vt3d_add (tmp, result, result);
02314 }
02315 
02316 /*---------------------------------------------------*/
02317 
02318 void vt3d_slerp (const VT3D p1, const VT3D p2, LIBGEOM_REAL u, VT3D result)
02319 
02320 { LIBGEOM_REAL dot = vt3d_get_dot (p1, p2);
02321   LIBGEOM_REAL omega = safe_acos (dot);
02322   VT3D tmp;
02323 
02324   if (omega < EPSIL_BIG_ZERO)
02325   {
02326     /* Linear interpolation */
02327 
02328     vt3d_mults (p1, 1.-u, tmp);
02329     vt3d_mults (p2, u, result);
02330   }
02331   else
02332   {
02333     LIBGEOM_REAL under = sin (omega),
02334              f1 = sin ((1.-u)*omega),
02335              f2 = sin (u*omega);
02336 
02337     vt3d_mults (p1, f1/under, tmp);
02338     vt3d_mults (p2, f2/under, result);
02339   }
02340 
02341   vt3d_add (tmp, result, result);
02342 }
02343 
02344 /*@#-------------------------------------------------------------------
02345     Public FUNCTION : 
02346     FUNCTIONALITY   : write the vector self in the file f.
02347     KEYWORD(S)      : 
02348     -------------------------------------------------------------------
02349     FUNCTION TYPE   : bool
02350     here parameter description with : flow / name / functionality  
02351     the flow can be one of  IN / OUT / IO (for IN and OUT)
02352     ---------------------------------------------------------------#@*/
02353 bool    vt3d_write(const VT3D self, FILE * f)
02354 {
02355   char *format_str;
02356 
02357   if (sizeof(LIBGEOM_REAL) == sizeof(float))
02358     format_str = "%f %f %f";
02359   else 
02360     format_str = "%lf %lf %lf";
02361 
02362     if(f)
02363     {
02364         fprintf(f, format_str, self[0], self[1], self[2]);
02365         
02366         return(true);
02367     }
02368     return(false);
02369 }
02370 
02371 /*@#-------------------------------------------------------------------
02372     Public FUNCTION : 
02373     FUNCTIONALITY   : read the vector self from the file f.
02374     KEYWORD(S)      : 
02375     -------------------------------------------------------------------
02376     FUNCTION TYPE   : bool
02377     here parameter description with : flow / name / functionality  
02378     the flow can be one of  IN / OUT / IO (for IN and OUT)
02379     ---------------------------------------------------------------#@*/
02380 bool    vt3d_read(VT3D self, FILE * f)
02381 {
02382   char *format_str;
02383 
02384   if (sizeof(LIBGEOM_REAL) == sizeof(float))
02385     format_str = "%f %f %f";
02386   else 
02387     format_str = "%lf %lf %lf";
02388 
02389     if(f)
02390     {
02391         fscanf(f, format_str, &self[0], &self[1], &self[2]);
02392         
02393         return(true);
02394     }
02395     return(false);
02396 }
02397 
02398 
02399 /*-------------------------------------------------------------------*/
02400 /*-------------------------------------------------------------------*/
02401 /* operations sur des vecteurs de dimension n Attention : l'utilisateur */
02402 /* est entierement responsable de la coherence de la dimension envoyee  */
02403 /* en parametre avec l'espace reserve par le pointeur.                  */
02404 /*-------------------------------------------------------------------*/
02405 
02406 double  *vtn_creation(int   n)
02407 {
02408         double  *p;
02409 
02410         if(n>0)
02411         {
02412           p = (double*) malloc((unsigned) n*sizeof(double));
02413           if(!p) {printf("erreur allocation memoire \n"); exit(0);}
02414 
02415           vtn_nul(p,n);
02416           return(p);
02417         }
02418         else return(NULL);
02419 }
02420 
02421 /*-------------------------------------------------------------------*/
02422 void    vtn_destr(double    *p)
02423 {
02424         if(p) free(p);
02425 }
02426 
02427 /*-------------------------------------------------------------------*/
02428 
02429 void    vtn_nul(double      *p, 
02430                 int         n)
02431 {
02432         int     i;
02433 
02434         if(p) for(i=0 ; i<n ; i++) p[i] = 0. ;
02435 }
02436 
02437 /*-------------------------------------------------------------------*/
02438 
02439 double  vtn_norm(const double       *p, 
02440                  int        n)
02441 {
02442         double  pnorm ;
02443         int     i;
02444 
02445         if(p)
02446         {
02447           for(i=0 , pnorm = 0. ; i<n ; i++) pnorm += p[i] * p[i] ;
02448           return(sqrt(pnorm)) ;
02449         }
02450         return(0.);
02451 }
02452 
02453 /*-------------------------------------------------------------------*/
02454 /* norme au premier degre minimisant les erreurs d'arrondi              */
02455 
02456 double  vtn_anorm(const double  *p, 
02457                   int           n)
02458 {
02459         double  anorm ;
02460         int     i ;
02461 
02462         if(p)
02463         {
02464           for(i=0 , anorm = 0. ; i<n ; i++) anorm += fabs(p[i]) ;
02465           return(anorm) ;
02466         }
02467         return(0.);
02468 }
02469 
02470 /*-------------------------------------------------------------------*/
02471 
02472 void    vtn_copy(const double   *psrc,
02473                  double *pdst, 
02474                  int            n)
02475 {
02476         int     i;
02477 
02478         if(psrc && pdst) for(i=0 ; i<n ; i++) pdst[i] = psrc[i] ;
02479 }
02480 
02481 
02482 /*-------------------------------------------------------------------*/
02483 
02484 void    vtn_add(const double        *p1,
02485                 const double        *p2,
02486                 double      *pdst, 
02487                 int         n)
02488 {
02489         int     i;
02490 
02491         if(p1 && p2 && pdst) for(i=0 ; i<n ; i++) pdst[i] = p1[i] + p2[i] ;
02492 }
02493 
02494 /*-------------------------------------------------------------------*/
02495 /* calcule   pdst = p1 - p2                                             */
02496 
02497 void    vtn_sub(const double        *p1,
02498                 const double        *p2,
02499                 double      *pdst, 
02500                 int         n)
02501 {
02502   int   i;
02503   
02504   if(p1 && p2 && pdst) 
02505     for(i=0 ; i<n ; i++) 
02506       pdst[i] = p1[i] - p2[i] ;
02507 }
02508 
02509 /*-------------------------------------------------------------------*/
02510 /* calcule   pdst = psrc * alpha                                */
02511 
02512 void vtn_mults (const double  *psrc, 
02513                 double  *pdst, 
02514                 int n, 
02515                 double  alpha)
02516 {
02517   int i;
02518   for (i=0 ; i<n ; i++) 
02519     pdst[i] = alpha * psrc[i];
02520 }
02521 
02522 
02523 /*-------------------------------------------------------------------*/
02524 /* calcule   pscal = produit scalaire (p1.p2)                           */
02525 
02526 double  vtn_dot(const double    *p1,
02527                 const double    *p2,
02528                 int         n)
02529 {
02530   int   i;
02531   double  pscal;
02532   
02533   if(p1 && p2)
02534    {
02535      pscal = 0. ;
02536      for(i=0 ; i<n ; i++) pscal += p1[i] * p2[i] ;
02537      return(pscal);
02538    }
02539   return(0.);
02540 }
02541 
02542 /*-------------------------------------------------------------------*/
02543 
02544 double  vtn_inv(const double        *p,
02545                 double      *p_inv, 
02546                 int         n)
02547 {
02548         double  pnorm2 ;
02549         int     i;
02550 
02551         if(p != NULL && p_inv != NULL)
02552         {
02553           for(i=0, pnorm2 = 0. ; i<n ; i++) pnorm2 += p[i] * p[i] ;
02554           if(pnorm2 > EPSIL_ZERO)
02555           { 
02556             for(i=0 ; i<n ; i++) p_inv[i] =  p[i] / pnorm2 ;
02557             return(pnorm2);
02558           }
02559           else
02560           {
02561             for(i=0 ; i<n ; i++) p_inv[i] = 0. ;
02562             printf("warning : inversion de vecteur nul  \n");
02563             return(0.);
02564           }
02565         }
02566         fprintf(stderr, "warning : vtn_inv() NULL pointer argument\n");
02567         return(0.);
02568 }
02569 
02570 
02571 
02572 
02573 
02574 /*-------------------------------------------------------------------*/
02575 /* operations sur des matrices mxn  ; Attention : l'utilisateur est     */
02576 /* entierement responsable de la consistance des dimensions envoyees    */
02577 /* en parametre avec l'espace reserve par les pointeurs.                */
02578 
02579 double  *matmxn_creation(int    lmax,
02580                          int    cmax)
02581 {
02582         double  *p;
02583 
02584         if((lmax>0)&&(cmax>0))
02585         {
02586           p = (double*) malloc((unsigned) lmax*cmax*sizeof(double));
02587           if(!p) {printf("erreur allocation memoire \n"); exit(0);}
02588 
02589           matmxn_nul(p,lmax,cmax);
02590           return(p);
02591         }
02592         else return(NULL);
02593 }
02594 
02595 /*-------------------------------------------------------------------*/
02596 
02597 void    matmxn_destr(double     *p)
02598 {
02599         if(p) free(p);
02600 }
02601 
02602 /*-------------------------------------------------------------------*/
02603 void    matmxn_nul(double       *p, 
02604                    int          lmax,
02605                    int          cmax)
02606 {
02607         int     i,
02608                 size = lmax * cmax;
02609 
02610         if(p)
02611           for(i=0 ; i<size ; i++)
02612             {
02613               *p = 0.;
02614               p++;
02615             }
02616 }
02617 
02618 /*-------------------------------------------------------------------*/
02619 void    matmxn_idt(double       *p, 
02620                    int          lmax,
02621                    int          cmax)
02622 {
02623         int i, min;
02624 
02625         if(p)
02626         {
02627           matmxn_nul (p, lmax, cmax);
02628 
02629           min = cmax<lmax ? cmax : lmax;
02630 
02631           for (i=0 ; i<min ; i++)
02632             VIJ (p,i,i,cmax)= 1. ;
02633         }
02634 }
02635 
02636 
02637 /*-------------------------------------------------------------------*/
02638 /*  copie le contenue de a vers b (pour i de 0 a lmax*cmax).            */
02639 
02640 void    matmxn_copy(const double * a, double * b, int lmax, int cmax)
02641 {
02642         int dmax, i ;
02643 
02644         dmax = lmax*cmax ;
02645 
02646         for(i=0 ; i<dmax ; i++, a++, b++) *b = *a ;
02647 }
02648 
02649 /*-------------------------------------------------------------------*/
02650 /*  calcule :   a(imax x jmax) * b(jamx x kmax) -> c(imax x kmax)       */
02651 
02652 void    matmxn_mult(const double        *a ,
02653                     const double        *b ,
02654                     double      *c , 
02655                     int         imax ,
02656                     int         jmax ,
02657                     int         kmax)
02658 { int i,j,k;
02659 
02660   if ((c != a) && (c != b))
02661     {
02662       for (i=0; i < imax; i++)
02663         for (k=0; k < kmax; k++)
02664           {
02665             double v = 0.;
02666 
02667             for (j=0; j < jmax; j++)
02668               v += VIJ (a,i,j,jmax) * VIJ (b,j,k,kmax);
02669 
02670             VIJ (c, i, k, kmax) = v;
02671           }
02672     }
02673   else
02674     {
02675         double  *ww;
02676 
02677         ww = matmxn_creation(imax,kmax);
02678 
02679         for(i=0 ; i<imax ; i++)
02680         {
02681           for(k=0 ; k<kmax ; k++)
02682           {
02683             double v = 0.;
02684 
02685             for(j=0 ; j<jmax ; j++)
02686               v += VIJ(a,i,j,jmax)*VIJ(b,j,k,kmax) ;
02687 
02688             VIJ(ww,i,k,kmax) = v;
02689           }
02690         }
02691 
02692         matmxn_copy (ww, c, imax, kmax);
02693 
02694         free(ww);
02695     }
02696 }
02697 
02698 /*-------------------------------------------------------------------*/
02699 /* calcule :  a(lmax x cmax) * b(cmax) -> c(lmax)                       */
02700 
02701 void    matmxn_mult_vtn(const double        *a ,
02702                         const double        *b ,
02703                         double      *c , 
02704                         int         lmax ,
02705                         int         cmax)
02706 {
02707         double  *w;
02708         int     i,j;
02709 
02710         w = vtn_creation(lmax);
02711 
02712         for(i=0 ; i<lmax ; i++)
02713         {
02714           w[i] = 0. ;
02715           for(j=0 ; j<cmax ; j++)
02716               w[i] += VIJ(a,i,j,cmax)*b[j] ;
02717         }
02718 
02719         for(i=0 ; i<lmax ; i++)
02720           c[i] = w[i] ;
02721 
02722         free(w);
02723 }
02724 
02725 /*-------------------------------------------------------------------*/
02726 
02727 void matmxn_write (double *d, int width, int height, FILE *f)
02728 
02729 { int i, j;
02730 
02731   for (i=0; i < height; i++)
02732   {
02733     for (j=0; j < width; j++)
02734       fprintf (f, "%f ", VIJ (d, i, j, width));
02735 
02736     fprintf (f, "\n");
02737   }
02738 }
02739 
02740 /*-------------------------------------------------------------------*/
02741 
02742 void matmxn_transpose (const double *src,
02743                        double *dest,
02744                        int    src_width,
02745                        int    src_height)
02746 
02747 { int i, j;
02748 
02749   if (src != dest)
02750     for (i=0; i < src_height; i++)
02751       for (j=0; j < src_width; j++)
02752         VIJ (dest, j, i, src_height) = VIJ (src, i, j, src_width);
02753   else
02754   {
02755     double *tmp = matmxn_creation (src_width, src_height);
02756 
02757     for (i=0; i < src_height; i++)
02758       for (j=0; j < src_width; j++)
02759         VIJ (tmp, j, i, src_height) = VIJ (src, i, j, src_width);
02760 
02761     matmxn_copy (tmp, dest, src_height, src_width);
02762 
02763     matmxn_destr (tmp);
02764   }
02765 }
02766 
02767 /*-------------------------------------------------------------------*/
02768 /* calcul de la pseudo inverse d'une matrice de lmax lignes sur cmax    */
02769 /* colonnes. Normallement lmax < cmax (redondance classique).           */
02770 
02771 
02772 bool    matmxn_pseudo_inverse(double    *m ,
02773                               int       lmax ,
02774                               int       cmax , 
02775                               double    *mp)
02776 {
02777         double  *a, *b, *c, *v;     /* vecteur colonne  de longueur lmax*/
02778         double  *d;                 /* vecteur ligne    de longueur cmax*/
02779 
02780         int     i,j,k;
02781         double  coef , anorm_a , anorm_c , seuil ;
02782 
02783         /*-----------------------------------------------------------*/
02784         /* allocation des vecteurs en fonction des dimensions du systeme*/
02785 
02786         a = vtn_creation(lmax);
02787         b = vtn_creation(lmax);
02788         c = vtn_creation(lmax);
02789         v = vtn_creation(lmax);
02790         d = vtn_creation(cmax);
02791 
02792         /*-----------------------------------------------------------*/
02793         /* traitement de la premiere colonne de la matrice m            */
02794 
02795         for(i=0 ; i<lmax ; i++) a[i] = VIJ(m,i,0,cmax);
02796         anorm_a = vtn_anorm(a,lmax);
02797 
02798         if(anorm_a < EPSIL_ZERO) for(i=0 ; i<lmax ; i++) VIJ(mp,0,i,lmax) = 0. ; 
02799         else
02800         {
02801           vtn_inv(a,v,lmax);
02802           for(i=0 ; i<lmax ; i++) VIJ(mp,0,i,lmax)  = v[i] ; 
02803         }
02804 
02805         /*-----------------------------------------------------------*/
02806         /* boucle de traitement de la colonne d'indice k                */
02807 
02808         for(k=1 ; k<cmax ; k++)
02809         {
02810           for(i=0 ; i<lmax ; i++)                   a[i] = VIJ(m,i,k,cmax) ;
02811           for(i=0 ; i<k    ; i++)           
02812             for(d[i] = 0. , j=0 ; j<lmax ; j++)     d[i] += VIJ(mp,i,j,lmax)*a[j] ;
02813 
02814           for(i=0 ; i<lmax ; i++)
02815             for(v[i] = 0. , j=0 ; j<k ; j++)        v[i] += VIJ(m,i,j,cmax)*d[j] ;
02816 
02817           for(i=0 ; i<lmax ; i++)                   c[i] = a[i] - v[i] ;
02818 
02819           anorm_a = vtn_anorm(a,lmax);
02820           anorm_c = vtn_anorm(c,lmax);
02821 
02822           seuil = SEUIL_GREV1*anorm_a ;
02823           if(anorm_c < seuil)
02824           {
02825             coef = 0. ;
02826             for(i=0 ; i<lmax   ; i++)         
02827               for(b[i] = 0. , j=0 ; j<k ; j++)      b[i] += d[j]*VIJ(mp,j,i,lmax);
02828 
02829             for(i=0 ; i<k    ; i++)                 coef += d[i]*d[i] ;
02830             coef = coef + 1. ;
02831             for(i=0 ; i<lmax ; i++)                 b[i] /= coef ;     
02832           }
02833           else
02834             vtn_inv(c,b,lmax);
02835           
02836           for(i=0 ; i<k    ; i++)
02837             for(j=0 ; j<lmax ; j++)
02838               VIJ(mp,i,j,lmax) -= d[i]*b[j];
02839 
02840           for(i=0 ; i<lmax ; i++)
02841             VIJ(mp,k,i,lmax) = b[i] ;
02842         }
02843 
02844         /*-----------------------------------------------------------*/
02845         /* liberation des vecteurs alloues                              */
02846 
02847         free(a) ; free(b) ; free(c) ; free(v) ; free(d) ;
02848 
02849         return(true);
02850 }
02851 
02852 /*------------------------------------------------------*/
02853 
02854 void matmxn_damped_least_square_inverse(double *j_inv, 
02855                                         double *j_mat, 
02856                                         int j_width, 
02857                                         int j_height, 
02858                                         double damping) 
02859 {
02860   double *J, *v, *w;
02861   int i, j, k;
02862   int height, width;
02863   
02864   if (j_width >=j_height) 
02865    {
02866       height = j_width;
02867       width  = j_width;
02868    } 
02869   else 
02870    {
02871      height = j_height;
02872      width  = j_width;
02873    }
02874   J = matmxn_creation(height,width);
02875   w = vtn_creation(width);
02876   v = matmxn_creation(width,width);
02877   
02878   for (i=0;i<j_height;i++)
02879     for (j=0;j<j_width;j++)
02880      {
02881        VIJ(J,i,j,width) = VIJ(j_mat,i,j,j_width);
02882      }
02883   
02884   svd(J,height,width,w,v);      
02885   
02886   Jinv(w,width,damping);
02887   
02888   for (i=0;i<width;i++)
02889     for (j=0;j<width;j++)
02890       VIJ(v,i,j,width) *= w[j];
02891 
02892   /* Compute : j_inv = v * transpose (J) */
02893 
02894   for (i=0;i<j_width;i++) 
02895     for (j=0;j<j_height;j++) 
02896      {
02897        double tmp = 0.;
02898        double *vline = v + i * width,
02899               *Jline = J + j * width;
02900 
02901        for (k=0;k<j_width;k++) 
02902          tmp += *(vline + k) * *(Jline + k);
02903 
02904        /* equivalent a :
02905 
02906          tmp += VIJ(v,i,k,width) * VIJ(J,j,k,width);
02907        */
02908 
02909        VIJ (j_inv,i,j,j_height) = tmp;
02910      }
02911   
02912   matmxn_destr(J);
02913   matmxn_destr(v);
02914   vtn_destr(w);
02915 }
02916 
02917 /*-------------------------------------------------------------------*/
02918 
02919 void matmxn_svdcmp(double **a,int m,int n,double *w,double **v) 
02920      /* Given a matrix a[1..m][1..n], this routine computes 
02921         its singular value decomposition. 
02922         A = U * W * Vt. The matrix U replaces a on output. The
02923         diagonal matrix of singular values W is output as
02924         vector w[1..n]. The matrix V (not the transpose Vt)
02925         is output as v[1..n][1..n]. 
02926         "Numerical Recipes in C", 2nd edition ! */
02927 {
02928 #define GEOM_SIGN(a,b)       ((b) >= 0.0 ? fabs(a) : -fabs(a))
02929 #define GEOM_MIN(a,b)        ((a) < (b) ? (a) : (b))
02930 
02931  /* anorm HAS to be float to avoid the svd to loop more than 30 times and then aborting... */
02932  int flag,i,its,j,jj,k,l,nm;
02933  double c,f,h,s,x,y,z;
02934  double g=0.0,scale=0.0;
02935  float anorm = 0.0;
02936  double *rv1;
02937 
02938   /* This test appears to be useless with 2nd edition of NR (c'est probabl.
02939      un reste de la 1ere edition de NR.
02940 
02941   if (m < n) 
02942     nrerror("matmxn_svdcmp: You must augment A with extra zero rows");
02943 
02944   */
02945 
02946                                 /* allocate a double vector with subscript */
02947                                 /* range v[nl..nh];  rv1=vector(1,n); */
02948   rv1=(double *)malloc((unsigned) (n)*sizeof(double))-1;
02949   if (!rv1) 
02950     nrerror("allocation failure in vector()");
02951 
02952   for (i=1;i<=n;i++) {
02953     l=i+1;
02954     rv1[i]=scale*g;
02955     g=s=scale=0.0;
02956     if (i <= m) {
02957       for (k=i;k<=m;k++) scale += fabs(a[k][i]);
02958       if (scale) {
02959         for (k=i;k<=m;k++) {
02960           a[k][i] /= scale;
02961           s += a[k][i]*a[k][i];
02962         }
02963         f=a[i][i];
02964         g = -GEOM_SIGN(sqrt(s),f);
02965         h=f*g-s;
02966         a[i][i]=f-g;
02967           for (j=l;j<=n;j++) {
02968             for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j];
02969             f=s/h;
02970             for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
02971           }
02972         for (k=i;k<=m;k++) a[k][i] *= scale;
02973       }
02974     }
02975     w[i]=scale*g;
02976     g=s=scale=0.0;
02977     if (i <= m && i != n) {
02978       for (k=l;k<=n;k++) scale += fabs(a[i][k]);
02979       if (scale) {
02980         for (k=l;k<=n;k++) {
02981           a[i][k] /= scale;
02982           s += a[i][k]*a[i][k];
02983         }
02984         f=a[i][l];
02985         g = -GEOM_SIGN(sqrt(s),f);
02986         h=f*g-s;
02987         a[i][l]=f-g;
02988         for (k=l;k<=n;k++) rv1[k]=a[i][k]/h;
02989           for (j=l;j<=m;j++) {
02990             for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k];
02991             for (k=l;k<=n;k++) a[j][k] += s*rv1[k];
02992           }
02993         for (k=l;k<=n;k++) a[i][k] *= scale;
02994       }
02995     }
02996     anorm=MAX(anorm,(fabs(w[i])+fabs(rv1[i])));
02997   }
02998   for (i=n;i>=1;i--) {
02999     if (i < n) {
03000       if (g) {
03001         for (j=l;j<=n;j++)
03002           v[j][i]=(a[i][j]/a[i][l])/g;
03003         for (j=l;j<=n;j++) {
03004           for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j];
03005           for (k=l;k<=n;k++) v[k][j] += s*v[k][i];
03006         }
03007       }
03008       for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0;
03009     }
03010     v[i][i]=1.0;
03011     g=rv1[i];
03012     l=i;
03013   }
03014   for (i=GEOM_MIN(m,n);i>=1;i--) {              /* Accumulation of left-hand transformations */
03015     l=i+1;
03016     g=w[i];
03017     for (j=l;j<=n;j++) a[i][j]=0.0;
03018     if (g) {
03019       g=1.0/g;
03020         for (j=l;j<=n;j++) {
03021           for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j];
03022           f=(s/a[i][i])*g;
03023           for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
03024       }
03025       for (j=i;j<=m;j++) a[j][i] *= g;
03026     } else {
03027       for (j=i;j<=m;j++) a[j][i]=0.0;
03028     }
03029     ++a[i][i];
03030   }
03031   for (k=n;k>=1;k--) {          /* diagonalization... */
03032     for (its=1;its<=30;its++) {
03033       flag=1;
03034       for (l=k;l>=1;l--) {
03035         nm=l-1;
03036     /* Keep the casts into float as they are! ==>> see comment above */
03037    if ((float)(fabs((float)rv1[l])+anorm) == anorm) {
03038      flag=0;
03039      break;
03040    }
03041    if ((float)(fabs((float)w[nm])+anorm) == anorm) break;
03042      }
03043      if (flag) {
03044    c=0.0;
03045    s=1.0;
03046    for (i=l;i<=k;i++) {
03047      f=s*rv1[i];
03048      rv1[i]=c*rv1[i];
03049      if ((float)(fabs((float)f)+anorm) == anorm) break; 
03050           g=w[i];
03051           h=pythag(f,g);
03052           w[i]=h;
03053           h=1.0/h;
03054           c=g*h;
03055           s= -f*h;
03056           for (j=1;j<=m;j++) {
03057             y=a[j][nm];
03058             z=a[j][i];
03059             a[j][nm]=y*c+z*s;
03060             a[j][i]=z*c-y*s;
03061           }
03062         }
03063       }
03064       z=w[k];
03065       if (l == k) {
03066         if (z < 0.0) {
03067           w[k] = -z;
03068           for (j=1;j<=n;j++) v[j][k] = -v[j][k];
03069         }
03070         break;
03071       }
03072       if (its == 30) 
03073         nrerror("No convergence in 30 matmxn_svdcmp iterations");
03074       x=w[l];
03075       nm=k-1;
03076       y=w[nm];
03077       g=rv1[nm];
03078       h=rv1[k];
03079       f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
03080       g=pythag(f,1.0);
03081       f=((x-z)*(x+z)+h*((y/(f+GEOM_SIGN(g,f)))-h))/x;
03082       c=s=1.0;                  /* Next QR transformation */
03083       for (j=l;j<=nm;j++) {
03084         i=j+1;
03085         g=rv1[i];
03086         y=w[i];
03087         h=s*g;
03088         g=c*g;
03089         z=pythag(f,h);
03090         rv1[j]=z;
03091         c=f/z;
03092         s=h/z;
03093         f=x*c+g*s;
03094         g=g*c-x*s;
03095         h=y*s;
03096         y=y*c;
03097         for (jj=1;jj<=n;jj++) {
03098           x=v[jj][j];
03099           z=v[jj][i];
03100           v[jj][j]=x*c+z*s;
03101           v[jj][i]=z*c-x*s;
03102         }
03103         z=pythag(f,h);
03104         w[j]=z;
03105         if (z) {
03106           z=1.0/z;
03107           c=f*z;
03108           s=h*z;
03109         }
03110         f=(c*g)+(s*y);
03111         x=(c*y)-(s*g);
03112         for (jj=1;jj<=m;jj++) {
03113           y=a[jj][j];
03114           z=a[jj][i];
03115           a[jj][j]=y*c+z*s;
03116           a[jj][i]=z*c-y*s;
03117         }
03118       }
03119       rv1[l]=0.0;
03120       rv1[k]=f;
03121       w[k]=x;
03122     }
03123   }
03124                                 /* free a double vector allocated with vector() */
03125                                 /* free_vector(rv1,1);*/
03126   free((char*) (rv1+1));
03127 #undef GEOM_MIN
03128 #undef GEOM_SIGN
03129 }
03130 /*------------------------------------------------------*/
03131 
03132 static
03133 void svd_invert
03134             (double  *target,
03135              double  *v,        /* will be exploded */
03136              double  *w,
03137              double  *J,
03138              int     width,
03139              int     height,
03140              bool transpose) /* Transpose target */
03141 
03142 { int i, j, k;
03143 
03144   for (i=0;i<width;i++)
03145     for (j=0;j<width;j++)
03146       VIJ(v,i,j,width) *= w[j];
03147 
03148   /* Compute : target = v * transpose (J) */
03149 
03150   for (i=0;i<width;i++) 
03151     for (j=0;j<height;j++) 
03152      {
03153        double tmp = 0.;
03154        double *vline = v + i * width,
03155               *Jline = J + j * width;
03156 
03157        for (k=0;k<width;k++) 
03158          tmp += *(vline + k) * *(Jline + k);
03159 
03160        /* equivalent a :
03161 
03162          tmp += VIJ(v,i,k,width) * VIJ(J,j,k,width);
03163        */
03164 
03165        if (transpose)
03166          VIJ (target, j, i, width) = tmp;
03167        else
03168          VIJ (target, i, j, height) = tmp;
03169      }
03170 }
03171 
03172 /*---------------------------------------------------------*/
03173 
03174 /* The following function computes the damped least square (DLS) inverse
03175    of matrix [height x width]; the damping is the maximum allowed norm
03176    for the solution of (matrix+ * task), where task is a vector or
03177    size height. The least square (LS) inverse (pseudoinverse) can also be
03178    computed at the same time (for about the same CPU time) if LS_inv
03179    is not NULL. Also, if task == NULL, it is assumed that task is a unit
03180    vector.
03181 */
03182 
03183 void matmxn_compute_LS_and_DLS_inverse (double *LS_inv,
03184                                         double *DLS_inv, 
03185                                         double *matrix, 
03186                                         int    width, 
03187                                         int    height, 
03188                                         double *task,
03189                                         double damping)
03190 
03191 { double  *u, *v, *w, *v2, *w2;
03192   int     i;
03193   bool is_horizontal = width > height;
03194 
03195   if (task != NULL)
03196     damping *= vtn_norm (task, height);
03197 
03198   /* For horizontal matrices, we compute the SVD of the transpose,
03199      because this is much faster (the order of complexity of the SVD
03200      is ~ width * width * height).
03201   */
03202 
03203   if (is_horizontal)
03204   {
03205     u = matmxn_creation (width, height);
03206 
03207     matmxn_transpose (matrix, u, width, height);
03208 
03209     /* Swap width and height (transpose) */
03210 
03211     i = width; width = height; height = i;
03212   }
03213   else
03214   {
03215     u = matmxn_creation (height, width);
03216 
03217     matmxn_copy (matrix, u, width, height);
03218   }
03219 
03220   v = matmxn_creation (width, width);
03221   v2= matmxn_creation (width, width);
03222   w = vtn_creation (width);
03223   w2= vtn_creation (width);
03224 
03225   svd (u,height,width,w,v);
03226 
03227   /* Compute LS-inverse if required */
03228 
03229   if (LS_inv != NULL)
03230   {
03231     matmxn_copy (v, v2, width, width);
03232     vtn_copy (w, w2, width);
03233 
03234     Jinv (w2, width, 0.);
03235 
03236     svd_invert (LS_inv, v2, w2, u, width, height, is_horizontal);
03237   }
03238 
03239   /* Compute DLS-inverse */
03240 
03241   Jinv (w, width, damping);
03242 
03243   svd_invert (DLS_inv, v, w, u, width, height, is_horizontal);
03244 
03245   matmxn_destr(u);
03246   matmxn_destr(v);
03247   matmxn_destr(v2);
03248   vtn_destr(w);
03249   vtn_destr(w2);
03250 }
03251 
03252 /*-------------------------------------------------------------------*/
03253 
03254 
03255 /* ================== QUATERNION FUNCTIONS =================== */
03256 
03257 /*
03258  * This library of functions performs operations on quaternions.
03259  *
03260  * added by L. Emering, Novembre 10, 1995
03261  *
03262  */
03263 
03264 /*------------------------------------------------------------------*/
03265 
03266 void quat_set(QUATERNION self, LIBGEOM_REAL w, LIBGEOM_REAL x, LIBGEOM_REAL y, LIBGEOM_REAL z)  
03267 {
03268   self[GEOM_W_INDEX] = w;
03269   self[GEOM_X_INDEX] = x;
03270   self[GEOM_Y_INDEX] = y;
03271   self[GEOM_Z_INDEX] = z;
03272 }
03273 
03274 /*------------------------------------------------------------------*/
03275 
03276 void quat_set_null (QUATERNION self)    
03277 {
03278   self[GEOM_W_INDEX] = 0.0;
03279   self[GEOM_X_INDEX] = 0.0;
03280   self[GEOM_Y_INDEX] = 0.0;
03281   self[GEOM_Z_INDEX] = 0.0;
03282 }
03283 
03284 /*------------------------------------------------------------------*/
03285 
03286 void quat_set_unit(QUATERNION self)             
03287 {
03288   self[GEOM_W_INDEX] = 1.0;
03289   self[GEOM_X_INDEX] = 0.0;
03290   self[GEOM_Y_INDEX] = 0.0;
03291   self[GEOM_Z_INDEX] = 0.0;
03292 }
03293 
03294 /*------------------------------------------------------------------*/
03295 
03296 void quat_assign (QUATERNION self, const QUATERNION newQuat)
03297 {
03298   self[GEOM_W_INDEX] = newQuat[GEOM_W_INDEX];
03299   self[GEOM_X_INDEX] = newQuat[GEOM_X_INDEX];
03300   self[GEOM_Y_INDEX] = newQuat[GEOM_Y_INDEX];
03301   self[GEOM_Z_INDEX] = newQuat[GEOM_Z_INDEX];
03302 }
03303 
03304 /*------------------------------------------------------------------*/
03305 
03306 void quat_copy (const QUATERNION src ,QUATERNION dest)
03307 {
03308   dest[GEOM_W_INDEX] = src [GEOM_W_INDEX];
03309   dest[GEOM_X_INDEX] = src [GEOM_X_INDEX];
03310   dest[GEOM_Y_INDEX] = src [GEOM_Y_INDEX];
03311   dest[GEOM_Z_INDEX] = src [GEOM_Z_INDEX];
03312 }
03313 
03314 /*------------------------------------------------------------------*/
03315 
03316 void quat_get_inv(const QUATERNION self, QUATERNION inv)        
03317 {
03318   LIBGEOM_REAL qn;
03319   
03320   qn = quat_dot(self, self);
03321   inv[GEOM_W_INDEX] =  self[GEOM_W_INDEX]/qn;
03322   inv[GEOM_X_INDEX] = -self[GEOM_X_INDEX]/qn;
03323   inv[GEOM_Y_INDEX] = -self[GEOM_Y_INDEX]/qn;
03324   inv[GEOM_Z_INDEX] = -self[GEOM_Z_INDEX]/qn;
03325 }
03326 
03327 /*------------------------------------------------------------------*/
03328 
03329 void quat_get_conj(const QUATERNION self, QUATERNION conj)      
03330 {
03331   conj[GEOM_W_INDEX] =  self[GEOM_W_INDEX];
03332   conj[GEOM_X_INDEX] = -self[GEOM_X_INDEX];
03333   conj[GEOM_Y_INDEX] = -self[GEOM_Y_INDEX];
03334   conj[GEOM_Z_INDEX] = -self[GEOM_Z_INDEX];
03335 }
03336 
03337 /*------------------------------------------------------------------*/
03338 
03339 LIBGEOM_REAL quat_get_norm(const QUATERNION self)       
03340 {
03341   return(sqrt((self[GEOM_W_INDEX]*self[GEOM_W_INDEX]) + 
03342               (self[GEOM_X_INDEX]*self[GEOM_X_INDEX]) + 
03343               (self[GEOM_Y_INDEX]*self[GEOM_Y_INDEX]) + 
03344               (self[GEOM_Z_INDEX]*self[GEOM_Z_INDEX])));
03345 }
03346 
03347 /*------------------------------------------------------------------*/
03348 
03349 LIBGEOM_REAL quat_get_distance (const QUATERNION left, const QUATERNION right)
03350 {
03351   QUATERNION qt;
03352   
03353   quat_sub(left, right, qt);
03354   return sqrt(quat_dot(qt,qt));
03355 }
03356 
03357 /*------------------------------------------------------------------*/
03358 
03359 LIBGEOM_REAL quat_get_sdistance (const QUATERNION left, const QUATERNION right)
03360 {
03361   QUATERNION q2n, qt;
03362   LIBGEOM_REAL dp, dn;
03363   
03364   quat_assign(q2n,right);
03365   quat_neg(q2n);
03366                                 /* calculate length of (Q1, +Q2) arc */
03367   quat_sub (left, right, qt);
03368   dp = quat_dot(qt, qt);
03369   
03370                                 /* calculate length of (Q1, -Q2) arc */
03371   quat_sub(left, q2n, qt);
03372   dn = quat_dot(qt, qt);
03373   return (dn < dp ? sqrt(dn) : sqrt(dp));
03374 }
03375 
03376 /*------------------------------------------------------------------*/
03377 
03378 void quat_neg(QUATERNION self)  
03379 {
03380   self[GEOM_W_INDEX] = -self[GEOM_W_INDEX];
03381   self[GEOM_X_INDEX] = -self[GEOM_X_INDEX];
03382   self[GEOM_Y_INDEX] = -self[GEOM_Y_INDEX];
03383   self[GEOM_Z_INDEX] = -self[GEOM_Z_INDEX];
03384 }
03385 
03386 /*------------------------------------------------------------------*/
03387 
03388 void quat_normalize (QUATERNION self)   
03389      /* normalizes a quaternion */
03390 {
03391   LIBGEOM_REAL qn = quat_get_norm(self);
03392   
03393   if (qn < EPSIL_BIG_ZERO)
03394    return;
03395   self[GEOM_W_INDEX] = self[GEOM_W_INDEX]/qn;
03396   self[GEOM_X_INDEX] = self[GEOM_X_INDEX]/qn;
03397   self[GEOM_Y_INDEX] = self[GEOM_Y_INDEX]/qn;
03398   self[GEOM_Z_INDEX] = self[GEOM_Z_INDEX]/qn;
03399 }
03400 
03401 /*------------------------------------------------------------------*/
03402 
03403 LIBGEOM_REAL quat_dot(const QUATERNION left, const QUATERNION right)
03404 {
03405   return ((left[GEOM_W_INDEX] * right[GEOM_W_INDEX]) + 
03406           (left[GEOM_X_INDEX] * right[GEOM_X_INDEX]) + 
03407           (left[GEOM_Y_INDEX] * right[GEOM_Y_INDEX]) + 
03408           (left[GEOM_Z_INDEX] * right[GEOM_Z_INDEX]));
03409 }
03410 
03411 /*------------------------------------------------------------------*/
03412 
03413 void quat_pow(const QUATERNION self, LIBGEOM_REAL alpha, QUATERNION result)
03414      /* raise a normalized quaternion to the power alpha */
03415 {
03416   LIBGEOM_REAL alphatheta, scale;
03417   
03418   scale = fsqrt((self[GEOM_X_INDEX] * self[GEOM_X_INDEX]) + 
03419                 (self[GEOM_Y_INDEX] * self[GEOM_Y_INDEX]) + 
03420                 (self[GEOM_Z_INDEX] * self[GEOM_Z_INDEX]));
03421   alphatheta = alpha * fatan2(scale, self[GEOM_W_INDEX]);
03422   if (scale > EPSIL_BIG_ZERO)
03423    scale = fsin(alphatheta)/scale;
03424   result[GEOM_W_INDEX] = fcos(alphatheta);
03425   result[GEOM_X_INDEX] = scale * self[GEOM_X_INDEX];
03426   result[GEOM_Y_INDEX] = scale * self[GEOM_Y_INDEX];
03427   result[GEOM_Z_INDEX] = scale * self[GEOM_Z_INDEX];
03428 }
03429 
03430 /*------------------------------------------------------------------*/
03431 
03432 void quat_exp(const QUATERNION self, QUATERNION result) 
03433      /* exponentiate quaternion, assuming LIBGEOM_REAL part 0 */
03434 {
03435   LIBGEOM_REAL theta, scale;
03436   
03437   theta = fsqrt((self[GEOM_X_INDEX]*self[GEOM_X_INDEX]) + 
03438                 (self[GEOM_Y_INDEX]*self[GEOM_Y_INDEX]) + 
03439                 (self[GEOM_Z_INDEX]*self[GEOM_Z_INDEX]));
03440   scale = 1.0;
03441   if (theta > EPSIL_BIG_ZERO)
03442    scale = fsin(theta)/theta;
03443   result[GEOM_W_INDEX] = fcos(theta);
03444   result[GEOM_X_INDEX] = scale * self[GEOM_X_INDEX];
03445   result[GEOM_Y_INDEX] = scale * self[GEOM_Y_INDEX];
03446   result[GEOM_Z_INDEX] = scale * self[GEOM_Z_INDEX];
03447 }
03448 
03449 /*------------------------------------------------------------------*/
03450 
03451 void quat_ln (const QUATERNION self, QUATERNION result) 
03452      /* take the natural logarithm of a normalized quaternion */
03453 {
03454   LIBGEOM_REAL theta, scale;
03455   
03456   scale = fsqrt((self[GEOM_X_INDEX]*self[GEOM_X_INDEX]) + 
03457                 (self[GEOM_Y_INDEX]*self[GEOM_Y_INDEX]) + 
03458                 (self[GEOM_Z_INDEX]*self[GEOM_Z_INDEX]));
03459   theta = fatan2(scale, self[GEOM_W_INDEX]);
03460   if (scale > EPSIL_BIG_ZERO)
03461    scale = theta/scale;
03462   result[GEOM_W_INDEX] = 0.0;
03463   result[GEOM_X_INDEX] = scale*self[GEOM_X_INDEX];
03464   result[GEOM_Y_INDEX] = scale*self[GEOM_Y_INDEX];
03465   result[GEOM_Z_INDEX] = scale*self[GEOM_Z_INDEX];
03466 }
03467 
03468 /*------------------------------------------------------------------*/
03469 
03470 void quat_mults (const QUATERNION self, LIBGEOM_REAL s, QUATERNION result)      
03471 {
03472   result[GEOM_W_INDEX] = self[GEOM_W_INDEX] * s;
03473   result[GEOM_X_INDEX] = self[GEOM_X_INDEX] * s;
03474   result[GEOM_Y_INDEX] = self[GEOM_Y_INDEX] * s;
03475   result[GEOM_Z_INDEX] = self[GEOM_Z_INDEX] * s;
03476 }
03477 
03478 /*------------------------------------------------------------------*/
03479 
03480 void quat_mult(const QUATERNION left, const QUATERNION right, QUATERNION result)
03481 {
03482   QUATERNION temp;
03483 
03484   temp[GEOM_W_INDEX]   = left[GEOM_W_INDEX]*right[GEOM_W_INDEX] - 
03485                           left[GEOM_X_INDEX]*right[GEOM_X_INDEX] - 
03486                            left[GEOM_Y_INDEX]*right[GEOM_Y_INDEX] - 
03487                             left[GEOM_Z_INDEX]*right[GEOM_Z_INDEX];
03488   temp[GEOM_X_INDEX]   = left[GEOM_W_INDEX]*right[GEOM_X_INDEX] + 
03489                           left[GEOM_X_INDEX]*right[GEOM_W_INDEX] + 
03490                            left[GEOM_Y_INDEX]*right[GEOM_Z_INDEX] - 
03491                             left[GEOM_Z_INDEX]*right[GEOM_Y_INDEX];
03492   temp[GEOM_Y_INDEX]   = left[GEOM_W_INDEX]*right[GEOM_Y_INDEX] + 
03493                           left[GEOM_Y_INDEX]*right[GEOM_W_INDEX] + 
03494                            left[GEOM_Z_INDEX]*right[GEOM_X_INDEX] - 
03495                             left[GEOM_X_INDEX]*right[GEOM_Z_INDEX];
03496   result[GEOM_Z_INDEX] = left[GEOM_W_INDEX]*right[GEOM_Z_INDEX] + 
03497                           left[GEOM_Z_INDEX]*right[GEOM_W_INDEX] + 
03498                            left[GEOM_X_INDEX]*right[GEOM_Y_INDEX] - 
03499                             left[GEOM_Y_INDEX]*right[GEOM_X_INDEX];
03500 
03501   result [GEOM_W_INDEX] = temp [GEOM_W_INDEX];
03502   result [GEOM_X_INDEX] = temp [GEOM_X_INDEX];
03503   result [GEOM_Y_INDEX] = temp [GEOM_Y_INDEX];
03504 }
03505 
03506 /*------------------------------------------------------------------*/
03507 
03508 void quat_sub (const QUATERNION left, const QUATERNION right, QUATERNION result)
03509 {
03510   result[GEOM_W_INDEX] = left[GEOM_W_INDEX]-right[GEOM_W_INDEX];
03511   result[GEOM_X_INDEX] = left[GEOM_X_INDEX]-right[GEOM_X_INDEX];
03512   result[GEOM_Y_INDEX] = left[GEOM_Y_INDEX]-right[GEOM_Y_INDEX];
03513   result[GEOM_Z_INDEX] = left[GEOM_Z_INDEX]-right[GEOM_Z_INDEX];
03514 }
03515 
03516 /*------------------------------------------------------------------*/
03517 
03518 void quat_add (const QUATERNION left, const QUATERNION right, QUATERNION result)
03519 {
03520   result[GEOM_W_INDEX] = left[GEOM_W_INDEX]+right[GEOM_W_INDEX];
03521   result[GEOM_X_INDEX] = left[GEOM_X_INDEX]+right[GEOM_X_INDEX];
03522   result[GEOM_Y_INDEX] = left[GEOM_Y_INDEX]+right[GEOM_Y_INDEX];
03523   result[GEOM_Z_INDEX] = left[GEOM_Z_INDEX]+right[GEOM_Z_INDEX];
03524 }
03525 
03526 /*------------------------------------------------------------------*/
03527 
03528 void quat_slerp (const QUATERNION left, const QUATERNION right,
03529                  LIBGEOM_REAL u, QUATERNION result)
03530 {
03531    QUATERNION qt1, qt2;
03532    LIBGEOM_REAL cs, sx, theta, scale1, scale2;
03533 
03534    cs = quat_dot(left, right);
03535 
03536    /* if quaternions are opposed, negate the second one */
03537    /* i.e. force quats to lie in the same hemisphere (this is due to the two-to-one mapping
03538       from unit quaternions to rotation matrices: R(q) = R(-q)) */
03539    if (cs < 0)
03540    {
03541       cs = -cs;
03542       quat_set(qt2, -right[GEOM_W_INDEX], -right[GEOM_X_INDEX], 
03543                -right[GEOM_Y_INDEX], -right[GEOM_Z_INDEX]);
03544    }
03545    else quat_copy (right, qt2);
03546 
03547    /* calculate coefficients */
03548 
03549    if (1.0-cs > EPSIL_BIG_ZERO)
03550    {
03551       theta = facos(cs);
03552       sx = fsin(theta);
03553       scale1 = fsin((1.0-u) * theta) / sx;
03554       scale2 = fsin(u * theta) / sx;
03555    }
03556    else
03557    {
03558       scale1 = 1.0 - u;
03559       scale2 = u;
03560    }
03561    
03562    quat_mults(left, scale1, qt1);
03563    quat_mults(qt2, scale2, qt2);
03564    quat_add (qt1, qt2, result);
03565 }
03566 
03567 /*------------------------------------------------------------------*/
03568 
03569 void quat_dump(const QUATERNION self)
03570 {
03571   printf("\nw:%f  x:%f  y:%f  z:%f", 
03572          self[GEOM_W_INDEX], 
03573          self[GEOM_X_INDEX], 
03574          self[GEOM_Y_INDEX], 
03575          self[GEOM_Z_INDEX]);
03576 }
03577 
03578 /*------------------------------------------------------------------*/
03579 
03580 void quat_from_axis (QUATERNION self, const VT3D axis, LIBGEOM_REAL angle)
03581 {
03582   LIBGEOM_REAL alpha = angle * 0.5;
03583   LIBGEOM_REAL sinAlpha = sin(alpha);
03584   
03585   self[GEOM_W_INDEX] = cos(alpha);
03586   self[GEOM_X_INDEX] = sinAlpha * axis[GEOM_X_INDEX];
03587   self[GEOM_Y_INDEX] = sinAlpha * axis[GEOM_Y_INDEX];
03588   self[GEOM_Z_INDEX] = sinAlpha * axis[GEOM_Z_INDEX];
03589 }
03590 
03591 /*------------------------------------------------------------------*/
03592 
03593 void quat_from_axis_angle (QUATERNION q, const VT3D axis_angle)
03594 
03595 {
03596   VT3D  axis;
03597   LIBGEOM_REAL norm = vt3d_get_norm (axis_angle);
03598   
03599   if (norm > EPSIL_BIG_ZERO)
03600     {
03601       vt3d_mults (axis_angle, 1./norm, axis);
03602       quat_from_axis (q, axis, norm);
03603     }
03604   else
03605     quat_set (q, 1., 0., 0., 0.);
03606 }
03607 
03608 /*------------------------------------------------------------------*/
03609 /* Converts a quaternion to an axis-angle whose norm is between 0 and PI. */
03610 
03611 void quat_to_axis_angle (const QUATERNION quat, VT3D axis)
03612 
03613 { double angle, norm, scalar;
03614 
03615   norm = sqrt(quat[0]*quat[0] + quat[1]*quat[1] + quat[2]*quat[2]) ;
03616 
03617   angle = 2. * safe_acos (quat [3]);
03618 
03619   if (norm > EPSILON)
03620   {
03621     if (angle > M_PI)
03622       scalar = (angle - 2.*M_PI) / norm;
03623     else
03624       scalar = angle / norm;
03625 
03626     axis[0] = (LIBGEOM_REAL) (scalar * quat[0]);
03627     axis[1] = (LIBGEOM_REAL) (scalar * quat[1]);
03628     axis[2] = (LIBGEOM_REAL) (scalar * quat[2]);
03629   }
03630   else
03631   {
03632      axis[0] = 0.;
03633      axis[1] = 0.;
03634      axis[2] = 0.;
03635   }
03636 }
03637 
03638 /*------------------------------------------------------------------*/
03639 /* Code taken from Gamasutra web site, article of July 1998.
03640    Replaces an old, buggy version.
03641 */
03642 
03643 void quat_from_matrix (const MatriX m, QUATERNION quat)
03644 
03645 { LIBGEOM_REAL  tr, s;
03646 
03647   tr = m[0][0] + m[1][1] + m[2][2];
03648 
03649   /* check the diagonal */
03650 
03651   if (tr > 0.0) {
03652     s = sqrt (tr + 1.0);
03653     quat[3] = s / 2.0;
03654     s = 0.5 / s;
03655     quat[0] = (m[1][2] - m[2][1]) * s;
03656     quat[1] = (m[2][0] - m[0][2]) * s;
03657     quat[2] = (m[0][1] - m[1][0]) * s;
03658   }
03659   else
03660   {
03661     int i, j, k;
03662     int nxt[3] = {1, 2, 0};
03663 
03664     /* diagonal is negative */
03665 
03666      if (m[1][1] > m[0][0])
03667        i = 1;
03668      else
03669        i = 0;
03670 
03671      if (m[2][2] > m[i][i])
03672        i = 2;
03673 
03674       j = nxt[i];
03675       k = nxt[j];
03676 
03677       s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
03678 
03679       quat[i] = s * 0.5;
03680 
03681       if (s != 0.0)   /* s should be never equal to 0 if matrix is orthogonal */
03682           s = 0.5 / s;
03683 
03684       quat[3] = (m[j][k] - m[k][j]) * s;
03685       quat[j] = (m[i][j] + m[j][i]) * s;
03686       quat[k] = (m[i][k] + m[k][i]) * s;
03687   }
03688 }
03689 
03690 /*------------------------------------------------------------------*/
03691 /* Code taken from Gamasutra web site, article of July 1998.
03692    Replaces an old, buggy version.
03693 */
03694 
03695 void quat_from_mr3d (const MR3D m, QUATERNION quat)
03696 
03697 { LIBGEOM_REAL  tr, s;
03698 
03699   tr = m[0][0] + m[1][1] + m[2][2];
03700 
03701   /* check the diagonal */
03702 
03703   if (tr > 0.0) {
03704     s = sqrt (tr + 1.0);
03705     quat[3] = s / 2.0;
03706     s = 0.5 / s;
03707     quat[0] = (m[1][2] - m[2][1]) * s;
03708     quat[1] = (m[2][0] - m[0][2]) * s;
03709     quat[2] = (m[0][1] - m[1][0]) * s;
03710   }
03711   else
03712   {
03713     int i, j, k;
03714     int nxt[3] = {1, 2, 0};
03715 
03716     /* diagonal is negative */
03717 
03718      if (m[1][1] > m[0][0])
03719        i = 1;
03720      else
03721        i = 0;
03722 
03723      if (m[2][2] > m[i][i])
03724        i = 2;
03725 
03726       j = nxt[i];
03727       k = nxt[j];
03728 
03729       s = sqrt ((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
03730 
03731       quat[i] = s * 0.5;
03732 
03733       if (s != 0.0)   /* s should be never equal to 0 if matrix is orthogonal */
03734           s = 0.5 / s;
03735 
03736       quat[3] = (m[j][k] - m[k][j]) * s;
03737       quat[j] = (m[i][j] + m[j][i]) * s;
03738       quat[k] = (m[i][k] + m[k][i]) * s;
03739   }
03740 }
03741 
03742 /*------------------------------------------------------------------*/
03743 
03744 void quat_to_matrix (const QUATERNION self, MatriX result)
03745 {
03746   LIBGEOM_REAL xx, yy, zz, xy, xz, yz, wx, wy, wz;
03747   LIBGEOM_REAL qnorm2;
03748 
03749   qnorm2 = 2.0f / (self[GEOM_X_INDEX]*self[GEOM_X_INDEX] + 
03750                    self[GEOM_Y_INDEX]*self[GEOM_Y_INDEX] + 
03751                    self[GEOM_Z_INDEX]*self[GEOM_Z_INDEX] + 
03752                    self[GEOM_W_INDEX]*self[GEOM_W_INDEX]);
03754   xx = qnorm2 * self[GEOM_X_INDEX];
03755   yy = qnorm2 * self[GEOM_Y_INDEX];
03756   zz = qnorm2 * self[GEOM_Z_INDEX] ;
03757   xy = xx * self[GEOM_Y_INDEX] ;
03758   xz = xx * self[GEOM_Z_INDEX] ;
03759   wx = xx * self[GEOM_W_INDEX] ;
03760   yz = yy * self[GEOM_Z_INDEX] ;
03761   wy = yy * self[GEOM_W_INDEX] ;
03762   wz = zz * self[GEOM_W_INDEX] ;
03763   xx *= self[GEOM_X_INDEX] ;
03764   yy *= self[GEOM_Y_INDEX] ;
03765   zz *= self[GEOM_Z_INDEX] ;
03766   
03767   result[0][0]= 1.0-yy-zz; result[0][1]= xy+wz;     
03768   result[0][2]= xz-wy;     result[0][3]= 0.0;
03769   result[1][0]= xy-wz;     result[1][1]= 1.0-xx-zz; 
03770   result[1][2]= yz+wx;     result[1][3]= 0.0;
03771   result[2][0]= xz+wy;     result[2][1]= yz-wx;     
03772   result[2][2]= 1.0-xx-yy; result[2][3]= 0.0;
03773   result[3][0]= 0.0;       result[3][1]= 0.0;       
03774   result[3][2]= 0.0;       result[3][3]= 1.0;
03775 }
03776 
03777 void quat_to_mr3d (const QUATERNION self, MR3D result)
03778 {
03779   LIBGEOM_REAL xx, yy, zz, xy, xz, yz, wx, wy, wz;
03780   LIBGEOM_REAL qnorm2;
03781 
03782   qnorm2 = 2.0f / (self[GEOM_X_INDEX]*self[GEOM_X_INDEX] + 
03783                    self[GEOM_Y_INDEX]*self[GEOM_Y_INDEX] + 
03784                    self[GEOM_Z_INDEX]*self[GEOM_Z_INDEX] + 
03785                    self[GEOM_W_INDEX]*self[GEOM_W_INDEX]);
03787   xx = qnorm2 * self[GEOM_X_INDEX];
03788   yy = qnorm2 * self[GEOM_Y_INDEX];
03789   zz = qnorm2 * self[GEOM_Z_INDEX] ;
03790   xy = xx * self[GEOM_Y_INDEX] ;
03791   xz = xx * self[GEOM_Z_INDEX] ;
03792   wx = xx * self[GEOM_W_INDEX] ;
03793   yz = yy * self[GEOM_Z_INDEX] ;
03794   wy = yy * self[GEOM_W_INDEX] ;
03795   wz = zz * self[GEOM_W_INDEX] ;
03796   xx *= self[GEOM_X_INDEX] ;
03797   yy *= self[GEOM_Y_INDEX] ;
03798   zz *= self[GEOM_Z_INDEX] ;
03799   
03800   result[0][0]= 1.0-yy-zz; result[0][1]= xy+wz;     
03801   result[0][2]= xz-wy;     
03802   result[1][0]= xy-wz;     result[1][1]= 1.0-xx-zz; 
03803   result[1][2]= yz+wx;     
03804   result[2][0]= xz+wy;     result[2][1]= yz-wx;     
03805   result[2][2]= 1.0-xx-yy; 
03806 }
03807 
03808 /*------------------------------------------------------------------*/
03809 /* Compute quaternion that performs a rotation that directly
03810    rotates v1 to v2.
03811 */
03812 
03813 void quat_from_two_vectors (const VT3D       v1,
03814                             const VT3D       v2,
03815                             QUATERNION q)
03816 
03817 { double dotp = vt3d_get_dot (v1, v2) + 1.;
03818 
03819   if (dotp > EPSIL_ZERO)
03820   {
03821     double c = sqrt (dotp * 0.5),
03822            d = 0.5 / c;
03823     VT3D   n;
03824   
03825     vt3d_cross (v1, v2, n);
03826 
03827     quat_set (q, c, n [0] * d, n [1] * d, n [2] * d);
03828   }
03829   else /* singularity : choose a solution among an infinity. */
03830   {
03831     quat_set (q, 0., 1., 0., 0.);
03832   }
03833 }
03834 
03835 /*------------------------------------------------------------------*/
03836 
03837 void quat_from_swing (QUATERNION q,
03838                       const LIBGEOM_REAL      swing [2])                      
03839 
03840 { 
03841   VT3D aa_swing;
03842 
03843   vt3d_let (swing [0], swing [1], 0., aa_swing);
03844   quat_from_axis_angle (q, aa_swing);
03845 }
03846 
03847 /*------------------------------------------------------------------*/
03848 
03849 void quat_from_swing_and_twist (QUATERNION q,
03850                                 const LIBGEOM_REAL      swing [2],
03851                                 LIBGEOM_REAL      twist)
03852 
03853 { QUATERNION qswing, qtwist;
03854   VT3D aa_swing, aa_twist;
03855 
03856   vt3d_let (swing [0], swing [1], 0.,    aa_swing);
03857   vt3d_let (0.,        0.,        twist, aa_twist);
03858 
03859   quat_from_axis_angle (qswing, aa_swing);
03860   quat_from_axis_angle (qtwist, aa_twist);
03861 
03862   quat_mult (qswing, qtwist, q);
03863 }
03864 
03865 /*------------------------------------------------------------------*/
03866 
03867 void quat_to_swing_and_twist (const QUATERNION q,
03868                               LIBGEOM_REAL      swing [2],
03869                               LIBGEOM_REAL      *twist)
03870 
03871 { LIBGEOM_REAL beta, s1, s2, gamma, sin_gamma, cos_gamma, fact;
03872 
03873   s1 = q [3] * q [3] + q [2] * q [2];
03874   s2 = q [0] * q [0] + q [1] * q [1];
03875 
03876   beta = atan2 (sqrt (s1*s2), s1);
03877 
03878   gamma = atan2 (q [2], q [3]);
03879 
03880   *twist = 2. * gamma;
03881 
03882   sin_gamma = sin (gamma);
03883   cos_gamma = cos (gamma);
03884 
03885   if (fabs (beta) < 0.001)
03886     fact = 1.;
03887   else
03888     fact = beta / sin (beta);
03889 
03890   fact *= 2.;
03891 
03892   swing [0] = fact * (cos_gamma * q [0] - sin_gamma * q [1]);
03893   swing [1] = fact * (sin_gamma * q [0] + cos_gamma * q [1]);
03894 }
03895 
03896 /*------------------------------------------------------*/
03897 
03898 /*-------------------------------------------------------------------*/
03899 /* ARRAY 1D                                                          */
03900 /*-------------------------------------------------------------------*/
03901 
03902 ARRAY1D *array1d_creation (int lines)
03903 
03904 { ARRAY1D *array1d = (ARRAY1D *) malloc (sizeof (ARRAY1D));
03905 
03906   if (array1d)
03907   {
03908     array1d->data = vtn_creation (lines);
03909     array1d->lines = lines;
03910   }
03911 
03912   return array1d;
03913 }
03914 
03915 /*-------------------------------------------------------------------*/
03916 
03917 void array1d_destroy (ARRAY1D *array1d)
03918 
03919 { if (array1d)
03920   {
03921     vtn_destr (array1d->data);
03922     free (array1d);
03923   }
03924 }
03925 
03926 /*-------------------------------------------------------------------*/
03927 
03928 void array1d_nul (ARRAY1D *array1d)
03929 
03930 { vtn_nul (array1d->data, array1d->lines); }
03931 
03932 /*-------------------------------------------------------------------*/
03933 
03934 double array1d_norm (ARRAY1D *array1d)
03935 
03936 { return vtn_norm (array1d->data, array1d->lines); }
03937 
03938 /*-------------------------------------------------------------------*/
03939 
03940 double array1d_anorm (ARRAY1D *array1d)
03941 
03942 { return vtn_anorm (array1d->data, array1d->lines); }
03943 
03944 /*-------------------------------------------------------------------*/
03945 
03946 void array1d_copy (ARRAY1D *src,
03947                    ARRAY1D *dest)
03948 
03949 { assert (src->lines == dest->lines);
03950 
03951   vtn_copy (src->data, dest->data, src->lines);
03952 }
03953 
03954 /*-------------------------------------------------------------------*/
03955 
03956 void array1d_add (ARRAY1D *src_left,
03957                   ARRAY1D *src_right,
03958                   ARRAY1D *dest)
03959 
03960 { assert (src_left->lines == src_right->lines);
03961   assert (src_left->lines == dest->lines);
03962 
03963   vtn_add (src_left->data, src_right->data, dest->data, dest->lines);
03964 }
03965 
03966 /*-------------------------------------------------------------------*/
03967 
03968 void array1d_sub (ARRAY1D *src_left,
03969                   ARRAY1D *src_right,
03970                   ARRAY1D *dest)
03971 
03972 { assert (src_left->lines == src_right->lines);
03973   assert (src_left->lines == dest->lines);
03974 
03975   vtn_sub (src_left->data, src_right->data, dest->data, dest->lines);
03976 }
03977 
03978 /*-------------------------------------------------------------------*/
03979 
03980 void array1d_mults (ARRAY1D *src,
03981                     ARRAY1D *dest,
03982                     double  factor)
03983 
03984 { assert (src->lines == dest->lines);
03985 
03986   vtn_mults (src->data, dest->data, src->lines, factor);
03987 }
03988 
03989 /*-------------------------------------------------------------------*/
03990 
03991 double array1d_dot (ARRAY1D *src1,
03992                     ARRAY1D *src2)
03993 
03994 { assert (src1->lines == src2->lines);
03995 
03996   return vtn_dot (src1->data, src2->data, src1->lines);
03997 }
03998 
03999 /*-------------------------------------------------------------------*/
04000 
04001 double array1d_inv (ARRAY1D *src,
04002                     ARRAY1D *dest)
04003 
04004 { assert (src->lines == dest->lines);
04005 
04006   return vtn_inv (src->data, dest->data, src->lines);
04007 }
04008 
04009 /*-------------------------------------------------------------------*/
04010 
04011 void array1d_write (ARRAY1D *a,
04012                     FILE    *file)
04013 
04014 { int i;
04015 
04016   for (i=0; i < a->lines; i++)
04017     fprintf (file, "%f\n", AI (a, i));
04018 }
04019 
04020 /*-------------------------------------------------------------------*/
04021 /* ARRAY 2D                                                          */
04022 /*-------------------------------------------------------------------*/
04023 
04024 ARRAY2D *array2d_creation (int lines,
04025                            int cols)
04026 
04027 { ARRAY2D *array2d = (ARRAY2D *) malloc (sizeof (ARRAY2D));
04028 
04029   if (array2d)
04030   {
04031     array2d->data  = matmxn_creation (lines, cols);
04032     array2d->lines = lines;
04033     array2d->cols  = cols;
04034   }
04035 
04036   return array2d;
04037 }
04038 
04039 /*-------------------------------------------------------------------*/
04040 
04041 void array2d_destroy (ARRAY2D *array2d)
04042 
04043 { if (array2d)
04044   {
04045     matmxn_destr (array2d->data);
04046     free (array2d);
04047   }
04048 }
04049 
04050 /*-------------------------------------------------------------------*/
04051 
04052 int  array2d_same_size (ARRAY2D *a,
04053                         ARRAY2D *b)
04054 
04055 { return (a->lines == b->lines) && (a->cols == b->cols); }
04056 
04057 /*-------------------------------------------------------------------*/
04058 
04059 void array2d_nul (ARRAY2D *array2d)
04060 
04061 { matmxn_nul (array2d->data, array2d->lines, array2d->cols); }
04062 
04063 /*-------------------------------------------------------------------*/
04064 
04065 void array2d_idt (ARRAY2D *array2d)
04066 
04067 { matmxn_idt (array2d->data, array2d->lines, array2d->cols); }
04068 
04069 /*-------------------------------------------------------------------*/
04070 
04071 void array2d_copy (ARRAY2D *src,
04072                    ARRAY2D *dest)
04073 
04074 { assert (src->lines == dest->lines);
04075   assert (src->cols  == dest->cols);
04076 
04077   matmxn_copy (src->data, dest->data, src->lines, src->cols);
04078 }
04079 
04080 /*-------------------------------------------------------------------*/
04081 
04082 void array2d_mult (ARRAY2D *a,
04083                    ARRAY2D *b,
04084                    ARRAY2D *dest)
04085 
04086 { assert (a->cols  == b->lines);
04087   assert (a->lines == dest->lines);
04088   assert (b->cols  == dest->cols);
04089 
04090   matmxn_mult (a->data, b->data, dest->data, a->lines, a->cols, b->cols);
04091 }
04092 
04093 /*-------------------------------------------------------------------*/
04094 
04095 void array2d_add (ARRAY2D *a,
04096                   ARRAY2D *b,
04097                   ARRAY2D *dest)
04098 
04099 { int size;
04100   double *ap    = a->data,
04101          *bp    = b->data,
04102          *destp = dest->data;
04103 
04104   assert (array2d_same_size (a, b) && array2d_same_size (a, dest));
04105 
04106   size = a->lines * a->cols;
04107 
04108   while (size-- > 0)
04109   {
04110     *destp = *ap + *bp;
04111 
04112     ap++;
04113     bp++;
04114     destp++;
04115   }
04116 }
04117 
04118 /*-------------------------------------------------------------------*/
04119 
04120 void array2d_sub (ARRAY2D *a,
04121                   ARRAY2D *b,
04122                   ARRAY2D *dest)
04123 
04124 { int size;
04125   double *ap    = a->data,
04126          *bp    = b->data,
04127          *destp = dest->data;
04128 
04129   assert (array2d_same_size (a, b) && array2d_same_size (a, dest));
04130 
04131   size = a->lines * a->cols;
04132 
04133   while (size-- > 0)
04134   {
04135     *destp = *ap - *bp;
04136 
04137     ap++;
04138     bp++;
04139     destp++;
04140   }
04141 }
04142 
04143 /*-------------------------------------------------------------------*/
04144 
04145 void array2d_mult_array1d (ARRAY2D *array2d,
04146                            ARRAY1D *array1d,
04147                            ARRAY1D *dest)
04148 
04149 { assert (array2d->cols  == array1d->lines);
04150   assert (array2d->lines == dest->lines);
04151 
04152   matmxn_mult_vtn (array2d->data, array1d->data, dest->data,
04153                    array2d->lines, array2d->cols);
04154 }
04155 
04156 /*-------------------------------------------------------------------*/
04157 
04158 void array2d_scale (ARRAY2D *src, 
04159                     float   scalar,
04160                     ARRAY2D *dest)
04161 
04162 { int i, j;
04163 
04164   assert (src->lines == dest->lines);
04165   assert (src->cols  == dest->cols);
04166 
04167   for (i=0; i < src->lines; i++)
04168     for (j=0; j < src->cols; j++)
04169       AIJ (dest, i, j) = AIJ (src, i, j) * scalar;
04170 }
04171 
04172 /*-------------------------------------------------------------------*/
04173 
04174 void array2d_pseudo_inverse (ARRAY2D *src,
04175                              ARRAY2D *dest)
04176 
04177 { assert (src->lines == dest->cols);
04178   assert (src->cols == dest->lines);
04179 
04180   matmxn_pseudo_inverse (src->data, src->lines, src->cols, dest->data);
04181 }
04182 
04183 /*-------------------------------------------------------------------*/
04184 
04185 void array2d_damped_least_square_inverse (ARRAY2D *j_inv,    /* output */
04186                                           ARRAY2D *j_mat,    /* input  */
04187                                           double  damping)
04188 
04189 { matmxn_damped_least_square_inverse (j_inv->data, j_mat->data, j_mat->cols, j_mat->lines, damping); }
04190 
04191 /*-------------------------------------------------------------------*/
04192 
04193 void array2d_compute_LS_and_DLS_inverse (ARRAY2D *LS_inv,   /* output LS-inverse  */
04194                                          ARRAY2D *DLS_inv,  /* output DLS-inverse */
04195                                          ARRAY2D *j_mat,    /* input matrix       */
04196                                          ARRAY1D *task,     /* (see relative matmxn_ function) */
04197                                          double  damping)   /* for DLS-inverse    */
04198 
04199 { matmxn_compute_LS_and_DLS_inverse (LS_inv == NULL ? NULL : LS_inv->data,
04200                                      DLS_inv->data, j_mat->data,
04201                                      j_mat->cols, j_mat->lines, task->data, damping);
04202 }
04203 
04204 /*-------------------------------------------------------------------*/
04205 
04206 void array2d_write (ARRAY2D *a,
04207                     FILE    *file)
04208 
04209 { int i, j;
04210 
04211   for (i=0; i < a->lines; i++)
04212   {
04213     for (j=0; j < a->cols; j++)
04214       fprintf (file, "%f ", AIJ (a, i, j));
04215 
04216     fprintf (file, "\n");
04217   }
04218 }
04219 
04220 /*-------------------------------------------------------------------*/
04221 
04222 void array2d_set_column (ARRAY2D *array2d,
04223                          int     column,
04224                          double  value)
04225 
04226 { int    lines;
04227   double *data;
04228 
04229   assert ((array2d != NULL) && (column < array2d->cols) && (column >= 0));
04230 
04231   lines = array2d->lines;
04232   data  = array2d->data + column;
04233 
04234   while (lines-- > 0)
04235   {
04236     *data = value;
04237     data += array2d->cols;
04238   }
04239 }
04240 
04241 /*-------------------------------------------------------------------*/
04242 
04243 void array2d_set_line (ARRAY2D *array2d,
04244                        int     line,
04245                        double  value)
04246 
04247 { int    cols;
04248   double *data;
04249 
04250   assert ((array2d != NULL) && (line < array2d->lines) && (line >= 0));
04251 
04252   cols = array2d->cols;
04253   data = array2d->data + line * cols;
04254 
04255   while (cols-- > 0)
04256   {
04257     *data = value;
04258     data++;
04259   }
04260 }
04261 
04262 /*-------------------------------------------------------------------*/
04263 
04264 void array2d_transpose (ARRAY2D *src,
04265                         ARRAY2D *dest)
04266 
04267 { assert (dest->lines == src->cols);
04268   assert (dest->cols == src->lines);
04269 
04270   matmxn_transpose (src->data, dest->data, src->cols, src->lines);
04271 }
04272 
04273 /*-------------------------------------------------------------------*/
04274 /* Functions to solve polynomials of 2nd, 3rt and 4th degree.        */
04275 /* Source: graphics gems                                             */
04276 /*-------------------------------------------------------------------*/
04277 
04278 /* epsilon surrounding for near zero values */
04279 
04280 #define     EQN_EPS     1e-9
04281 #define     IsZero(x)   ((x) > -EQN_EPS && (x) < EQN_EPS)
04282 
04283 #define     CBRT(x)     ((x) > 0.0 ? pow((double)(x), 1.0/3.0) : \
04284                           ((x) < 0.0 ? -pow((double)-(x), 1.0/3.0) : 0.0))
04285 
04286 int polynomial_solve_quadric (double c[3], double s[2])
04287 {
04288     double p, q, D;
04289 
04290     /* normal form: x^2 + px + q = 0 */
04291 
04292     p = c[ 1 ] / (2 * c[ 2 ]);
04293     q = c[ 0 ] / c[ 2 ];
04294 
04295     D = p * p - q;
04296 
04297     if (IsZero(D))
04298     {
04299         s[ 0 ] = - p;
04300         return 1;
04301     }
04302     else if (D < 0)
04303     {
04304         return 0;
04305     }
04306     else /* if (D > 0) */
04307     {
04308         double sqrt_D = sqrt(D);
04309 
04310         s[ 0 ] =   sqrt_D - p;
04311         s[ 1 ] = - sqrt_D - p;
04312         return 2;
04313     }
04314 }
04315 
04316 
04317 int polynomial_solve_cubic (double c[4], double s[3])
04318 {
04319     int     i, num;
04320     double  sub;
04321     double  A, B, C;
04322     double  sq_A, p, q;
04323     double  cb_p, D;
04324 
04325     /* normal form: x^3 + Ax^2 + Bx + C = 0 */
04326 
04327     A = c[ 2 ] / c[ 3 ];
04328     B = c[ 1 ] / c[ 3 ];
04329     C = c[ 0 ] / c[ 3 ];
04330 
04331     /*  substitute x = y - A/3 to eliminate quadric term:
04332         x^3 +px + q = 0 */
04333 
04334     sq_A = A * A;
04335     p = 1.0/3 * (- 1.0/3 * sq_A + B);
04336     q = 1.0/2 * (A * (2.0/27 * sq_A - 1.0/3 * B) + C);
04337 
04338     /* use Cardano's formula */
04339 
04340     cb_p = p * p * p;
04341     D = q * q + cb_p;
04342 
04343     if (IsZero(D))
04344     {
04345         if (IsZero(q)) /* one triple solution */
04346         {
04347             s[ 0 ] = 0;
04348             num = 1;
04349         }
04350         else /* one single and one double solution */
04351         {
04352             double u = CBRT(-q);
04353             s[ 0 ] = 2 * u;
04354             s[ 1 ] = - u;
04355             num = 2;
04356         }
04357     }
04358     else if (D < 0) /* Casus irreducibilis: three real solutions */
04359     {
04360         double phi = 1.0/3 * acos(-q / sqrt(-cb_p));
04361         double t = 2 * sqrt(-p);
04362 
04363         s[ 0 ] =   t * cos(phi);
04364         s[ 1 ] = - t * cos(phi + M_PI / 3);
04365         s[ 2 ] = - t * cos(phi - M_PI / 3);
04366         num = 3;
04367     }
04368     else /* one real solution */
04369     {
04370         double sqrt_D = sqrt(D);
04371         double u = CBRT(sqrt_D - q);
04372         double v = - CBRT(sqrt_D + q);
04373 
04374         s[ 0 ] = u + v;
04375         num = 1;
04376     }
04377 
04378     /* resubstitute */
04379 
04380     sub = 1.0/3 * A;
04381 
04382     for (i = 0; i < num; ++i)
04383         s[ i ] -= sub;
04384 
04385     return num;
04386 }
04387 
04388 
04389 int polynomial_solve_quartic(double c[5], double s[4])
04390 {
04391     double  coeffs[ 4 ];
04392     double  z, u, v, sub;
04393     double  A, B, C, D;
04394     double  sq_A, p, q, r;
04395     int     i, num;
04396 
04397     /* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */
04398 
04399     A = c[ 3 ] / c[ 4 ];
04400     B = c[ 2 ] / c[ 4 ];
04401     C = c[ 1 ] / c[ 4 ];
04402     D = c[ 0 ] / c[ 4 ];
04403 
04404     /*  substitute x = y - A/4 to eliminate cubic term:
04405         x^4 + px^2 + qx + r = 0 */
04406 
04407     sq_A = A * A;
04408     p = - 3.0/8 * sq_A + B;
04409     q = A * (1.0/8 * sq_A - 1.0/2 * B) + C;
04410     r = sq_A * (- 3.0/256*sq_A + 1.0/16*B) - 1.0/4*A*C + D;
04411 
04412     if (IsZero(r))
04413     {
04414         /* no absolute term: y(y^3 + py + q) = 0 */
04415 
04416         coeffs[ 0 ] = q;
04417         coeffs[ 1 ] = p;
04418         coeffs[ 2 ] = 0;
04419         coeffs[ 3 ] = 1;
04420 
04421         num = polynomial_solve_cubic(coeffs, s);
04422 
04423         s[ num++ ] = 0;
04424     }
04425     else
04426     {
04427         /* solve the resolvent cubic ... */
04428 
04429         coeffs[ 0 ] = 1.0/2 * r * p - 1.0/8 * q * q;
04430         coeffs[ 1 ] = - r;
04431         coeffs[ 2 ] = - 1.0/2 * p;
04432         coeffs[ 3 ] = 1;
04433 
04434         (void) polynomial_solve_cubic(coeffs, s);
04435 
04436         /* ... and take the one real solution ... */
04437 
04438         z = s[ 0 ];
04439 
04440         /* ... to build two quadric equations */
04441 
04442         u = z * z - r;
04443         v = 2 * z - p;
04444 
04445         if (IsZero(u))
04446             u = 0;
04447         else if (u > 0)
04448             u = sqrt(u);
04449         else
04450             return 0;
04451 
04452         if (IsZero(v))
04453             v = 0;
04454         else if (v > 0)
04455             v = sqrt(v);
04456         else
04457             return 0;
04458 
04459         coeffs[ 0 ] = z - u;
04460         coeffs[ 1 ] = q < 0 ? -v : v;
04461         coeffs[ 2 ] = 1;
04462 
04463         num = polynomial_solve_quadric(coeffs, s);
04464 
04465         coeffs[ 0 ]= z + u;
04466         coeffs[ 1 ] = q < 0 ? v : -v;
04467         coeffs[ 2 ] = 1;
04468 
04469         num += polynomial_solve_quadric(coeffs, s + num);
04470     }
04471 
04472     /* resubstitute */
04473 
04474     sub = 1.0/4 * A;
04475 
04476     for (i = 0; i < num; ++i)
04477         s[ i ] -= sub;
04478 
04479     return num;
04480 }
04481 
04482 }

Generated on Thu Dec 1 10:13:37 2005 for COME - Biomechanical Joint Model by  doxygen 1.4.5