Skip to content
Snippets Groups Projects
Select Git revision
  • 1206d288caf4d3c43ddb9f6afbfa0701ebcf4f0b
  • master default protected
  • compilation2022apr
  • ISEI_3_5_1
  • VERSION_3_9-alba
  • VERSION_3_9-Indus2
  • Jianfeng
  • VERSION-3_10
  • VERSION-3_9_1
  • VERSION-3_9_alba
  • VERSION-3_9_Indus2
  • VERSION-3_9
  • VERSION-3_8
  • VERSION-3_7
  • ISEI_3_5_1-PATCH_2
  • ISEI_3_5_1-PATCH_1
  • PROD_3_5_1
  • VERSION_3_6prerelease2
  • VERSION_3_6prerelease
  • VERSION-3_5
  • tracy
21 results

nrframe.c

Blame
  • user avatar
    nadolski authored
    66664f7d
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    nrframe.c 13.17 KiB
    /* nrframe.c **************************************************************
    
      NR Library Package - Homogeneous Transformation Frames
    
      James Trevelyan,  University of Western Australia
      Revision 2   January 1996
    
    **************************************************************************/
    
    /* define V_CHECK to include validity checks on matrices */
    #define V_CHECK
    
    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #include <string.h>
    #include "nrlin.h"
    
    #define True 1
    #define False 0
    #define X 1
    #define Y 2
    #define Z 3
    #define U 4
    
    #ifdef TEST
    extern FILE *outfile;
    extern double **F1;
    #endif
    
    double **SCR;
    
    double **dframe( void )
    {
       return ( dmatrix( 1, 4, 1, 4 ) );
    }
    
    double *d4vector( void )
    {
       return ( dvector( 1, 4 ) );
    }
    
    void chainmult( double **a, double **b )
    /* multiply 4*4 matrices a, b into a, using SCR scratch matrix above */
    {   
       static int once = 0;
    
       if ( !once ) {
          SCR = dmatrix( 1,4, 1,4 );
          once = True;
       }
    #ifdef V_CHECK
       if ( !valid_dframe( a ) ) 
          nrerror("Invalid 1st matrix: chainmult\n"); 
       if ( !valid_dframe( b ) ) 
          nrerror("Invalid 2nd matrix: chainmult\n"); 
    #endif
       dmmult( a, 4, 4, b, 4, 4, SCR );
       dmcopy( SCR, 4, 4, a );
    }
    
    
    void rotframe( double **a, int axis, double theta) /* make a rotation transform */
    {
       double ca, sa;
       int i,j;
    
    #ifdef V_CHECK
       if ( !valid_dframe( a ) ) 
          nrerror("Invalid matrix: rotframe\n");
    #endif
       ca = cos(theta);
       sa = sin(theta);
       for (i=1; i<=4; i++)
          for (j=1; j<=4; j++) a[i][j] = 0.0;
       switch( axis) {
         case 3:
          a[4][4] = a[3][3] = 1.0;
          a[2][2] = a[1][1] = ca;
          a[1][2] = -sa;
          a[2][1] = sa;
          break;
         case 1:
          a[4][4] = a[1][1] = 1.0;
          a[2][2] = a[3][3] = ca;
          a[2][3] = -sa;
          a[3][2] = sa;
          break;
         case 2:
          a[4][4] = a[2][2] = 1.0;
          a[1][1] = a[3][3] = ca;
          a[3][1] = -sa;
          a[1][3] = sa;
          break;
         default: 
          fprintf(stderr, "rotframe: axis not X, Y or Z\n");
          exit(1);
          break;
       }
    }
    
    void transframe( double **a, double dx, double dy, double dz) 
    /* make a translation tr'm */
    {
       int i,j;
    
    #ifdef V_CHECK
       if ( !valid_dframe( a ) ) 
          nrerror("Invalid matrix: transframe\n");    
    #endif
       for (i=1; i<=4; i++)
          for (j=1; j<=4; j++) a[i][j] = 0.0;
       a[4][4] = a[3][3] = 1.0;
       a[2][2] = a[1][1] = 1.0;
       a[1][4] = dx;
       a[2][4] = dy;
       a[3][4] = dz;
    }
    
    
    void orthog( double **a ) /* orthogonalize a frame */
    {
       int i, j, k;
       double s;
    
    #ifdef V_CHECK
       if ( !valid_dframe( a ) ) 
          nrerror("Invalid matrix: orthog\n");    
    #endif
       /* cross j, k to produce i */
       a[1][1] = a[2][2]*a[3][3] - a[3][2]*a[2][3];
       a[2][1] = a[3][2]*a[1][3] - a[1][2]*a[3][3];
       a[3][1] = a[1][2]*a[2][3] - a[2][2]*a[1][3];
    
       /* normalize i, k */
       s = sqrt(DSQR(a[1][3]) + DSQR(a[2][3]) + DSQR(a[3][3]));
       for (i=1; i<=3; i++) a[i][3] /= s;
       s = sqrt(DSQR(a[1][1]) + DSQR(a[2][1]) + DSQR(a[3][1]));
       for (i=1; i<=3; i++) a[i][1] /= s;
    
       /* cross k, i to produce j */
       a[1][2] = a[2][3]*a[3][1] - a[3][3]*a[2][1];
       a[2][2] = a[3][3]*a[1][1] - a[1][3]*a[3][1];
       a[3][2] = a[1][3]*a[2][1] - a[2][3]*a[1][1];
    
    }
    
    void orthogKI( double **a ) /* orthogonalize a frame using K & I vector */
    {
       int i, j, k;
       double s;
    
    #ifdef V_CHECK
       if ( !valid_dframe( a ) )
          nrerror("Invalid matrix: orthog\n");
    #endif
       /* cross k, i to produce j */
       a[1][2] = a[2][3]*a[3][1] - a[3][3]*a[2][1];
       a[2][2] = a[3][3]*a[1][1] - a[1][3]*a[3][1];
       a[3][2] = a[1][3]*a[2][1] - a[2][3]*a[1][1];
    
       /* normalize j, k */
       s = sqrt(DSQR(a[1][3]) + DSQR(a[2][3]) + DSQR(a[3][3]));
       for (i=1; i<=3; i++) a[i][3] /= s;
       s = sqrt(DSQR(a[1][2]) + DSQR(a[2][2]) + DSQR(a[3][2]));
       for (i=1; i<=3; i++) a[i][2] /= s;
    
       /* cross j, k to produce i */
       a[1][1] = a[2][2]*a[3][3] - a[3][2]*a[2][3];
       a[2][1] = a[3][2]*a[1][3] - a[1][2]*a[3][3];
       a[3][1] = a[1][2]*a[2][3] - a[2][2]*a[1][3];
    
    }
    
    void dframeinverse( double **E, double **Ein ) /* form inverse frame */
    {
       double a[6], b[6];
       int i, j;
    
       validate_dvector( a, 1, 4);
       validate_dvector( b, 1, 4);
    
       for (i=1; i<=3; i++) {
          for (j=1; j<=3; j++) {
             Ein[i][j] = E[j][i];
          }
          Ein[4][i] = 0.0;
          Ein[i][4] = 0.0;
       }
       Ein[4][4] = 1.0;
    
       dgetcolumn(E, 4, a, 4);
       dmvmult(Ein, 4, 4, a, 4, b);
       for (i=1; i<=3; i++) Ein[i][4] = -b[i];
    }
    
    
    void dcross4 ( double *a, double *b, double *c ) /* cross two 4-vectors */
    {
       double x, y, z;
    
    #ifdef V_CHECK
       if ( !valid_d4vector_b( a ) ) 
          nrerror("Invalid vector 1: dcross4\n"); 
       if ( !valid_d4vector_b( b ) ) 
          nrerror("Invalid vector 2: dcross4\n"); 
       if ( !valid_d4vector_b( c ) ) 
          nrerror("Invalid vector 3: dcross4\n"); 
    #endif
       x = a[2]*b[3] - a[3]*b[2];
       y = a[3]*b[1] - a[1]*b[3];
       z = a[1]*b[2] - a[2]*b[1];
       c[1] = x; 
       c[2] = y; 
       c[3] = z; 
       c[4] = 0.0;
    }
    
    double column_dot( double **G1, int col1, double **G2, int col2 )
    /* form vector dot product of two columns (1st 3 elements only) */
    {
       int i;
       double sum;
    
    #ifdef V_CHECK
       if ( !valid_dframe( G1 ) ) 
          nrerror("Invalid 1st frame: column_dot\n"); 
       if ( !valid_dframe( G2 ) ) 
          nrerror("Invalid 2nd frame: column_dot\n"); 
    #endif
       sum = 0.0;
       for ( i=1; i<=3; i++ ) sum += G1[i][col1]*G2[i][col2];
       return(sum);
    }
    
    void make_d_omega( double **G1, double **G2, double *w)
    /* find small rotational difference between two frames G1, G2 */
    /* ref: Shear Magic 4A.27 p129 */
    {
    #ifdef V_CHECK
       if ( !valid_dframe( G1 ) ) 
          nrerror("Invalid 1st frame: make_d_omega\n");
       if ( !valid_dframe( G2 ) ) 
          nrerror("Invalid 2nd frame: make_d_omega\n");   
    #endif
       w[1] = column_dot( G1, 3, G2, 2 );
       w[2] = column_dot( G1, 1, G2, 3 );
       w[3] = column_dot( G1, 2, G2, 1 );
       w[4] = 0.0;
    }
    
    void compare_link_frames( double **G1, double **G2, double *wp, double *wr, double *ww )
    {
       double wrot[6], z1[6], z2[6], zz[6];
    
       validate_dvector(wrot, 1, 4);
       validate_dvector(z1, 1, 4);
       validate_dvector(z2, 1, 4);
       validate_dvector(zz, 1, 4);
    
    #ifdef V_CHECK
       if ( !valid_dframe( G1 ) ) 
          nrerror("Invalid 1st frame: compare_link_frames\n");    
       if ( !valid_dframe( G2 ) ) 
          nrerror("Invalid 2nd frame: compare_link_frames\n");    
    #endif
       *wp = *wr = *ww = 0.0;
       dgetcolumn( G1, Z, z1, 4 ); /* z axis comparison by cross product */
       dgetcolumn( G2, Z, z2, 4 );
       dcross4( z1, z2, zz );
       *wr = dvmag( zz, 3 );
    
       dgetcolumn( G1, U, z1, 4 ); /* origin comparison */
       dgetcolumn( G2, U, z2, 4 );
       dvsub( z1, 4, z2, zz );
       *wp = dvmag( zz, 3 );
    
       /*  printf("wp, wr, ww: %8.4lf %8.4lf %8.4lf\n", *wp, *wr, *ww ); */
    }
    
    void compare_frames( double **G1, double **G2, double *wp, double *wr, double *ww )
    {
       double wrot[6], z1[6], z2[6], zz[6];
    
       validate_dvector(wrot, 1, 4);
       validate_dvector(z1, 1, 4);
       validate_dvector(z2, 1, 4);
       validate_dvector(zz, 1, 4);
    
    #ifdef V_CHECK
       if ( !valid_dframe( G1 ) ) 
          nrerror("Invalid 1st frame: compare_frames\n"); 
       if ( !valid_dframe( G2 ) ) 
          nrerror("Invalid 2nd frame: compare_frames\n"); 
    #endif
       *wp = *wr = *ww = 0.0;
       make_d_omega( G1, G2, wrot );   
       *wr = dvmag( wrot, 3 );
       *wp = sqrt( DSQR(G1[X][U] - G2[X][U]) 
          + DSQR(G1[Y][U] - G2[Y][U]) 
          + DSQR(G1[Z][U] - G2[Z][U]) );
       *ww = sqrt( DSQR(*wr) + DSQR(*wp) );
       /*  printf("wp, wr, ww: %8.4lf %8.4lf %8.4lf\n", *wp, *wr, *ww ); */
    }
    
    /*------------------------------------------------------------*/
    void FindAxis(double **T1, double **T2, double *axis,
                    double *sphi, double *cphi,int *twitching)
    {
       /*  Routine to find the axis of rotation between two frames and the angle between them.
       */
    
       static double **FF;
       static int done_once = False;
       double ca[6],cb[6],cc[6],cd[6]; /*   workspace vectors   */
       double da[6],db[6],dc[6],dd[6]; /*   workspace vectors   */
       double d1, d2, d3, dmax;
    
       validate_dvector(ca, 1, 4);
       validate_dvector(cb, 1, 4);
       validate_dvector(cc, 1, 4);
       validate_dvector(cd, 1, 4);
       validate_dvector(da, 1, 4);
       validate_dvector(db, 1, 4);
       validate_dvector(dc, 1, 4);
       validate_dvector(dd, 1, 4);
    
       if (!done_once) {
          FF = dmatrix( 1, 4, 1, 4 );
          done_once = True;
       }
    
    #ifdef V_CHECK
       if ( !valid_dframe( T1 ) ) 
          nrerror("Invalid 1st frame: FindAxis\n");   
       if ( !valid_dframe( T2 ) ) 
          nrerror("Invalid 2nd frame: FindAxis\n");   
       if ( !valid_d4vector_b( axis ) )
          nrerror("Invalid axis vector: FindAxis\n"); 
    #endif
    
       *twitching = False;
    
       /*  Find axis of rotation */
    
       dmsub(T2, 4, 4, T1, FF);             /*  Difference of transforms    */
       dgetcolumn(FF, X, ca, 4);
       dgetcolumn(FF, Y, cb, 4);
       dgetcolumn(FF, Z, cc, 4);
       dcross4( ca, cb, da );
       dcross4( cb, cc, db );
       dcross4( cc, ca, dc );
       d1 = dvmnorm( da, 3 );
       d2 = dvmnorm( db, 3 );
       d3 = dvmnorm( dc, 3 );
       if ( d1 < d2 ) {
          if ( d2 < d3 ) {
             dvcopy( dc, 4, axis );
             dmax = d3;
          } 
          else {
             dvcopy( db, 4, axis );
             dmax = d2;
          }
       } 
       else {
          if ( d1 < d3 ) {
             dvcopy( dc, 4, axis );
             dmax = d3;
          } 
          else {
             dvcopy( da, 4, axis );
             dmax = d1;
          }
       }
       /*    printf("dmax = %12.6lf\n", dmax); */
       if( dmax < 0.000001 ) {                  /* there is no rotation, or we have a problem  */
          d1 = column_dot( T1, X, T2, X);
          d2 = column_dot( T1, Y, T2, Y);
          d3 = column_dot( T1, Z, T2, Z);
          if( d1<0.5 || d2<0.5 || d3<0.5 ) { /* problem */
             fprintf( stderr, "FindAxis: Frames opposed to each other\n");
             dgetcolumn(T1, Z, axis, 4);      /* Set axis to k vector and angle */
             *cphi = 1.0;                     /* to zero.  */
             *sphi = 0.0;
             return;
          } 
          else {                             /* Orientation change is small */
             *twitching = True;
             ca[1] = column_dot( T1, 3, T2, 2 );
             ca[2] = column_dot( T1, 1, T2, 3 );
             ca[3] = column_dot( T1, 2, T2, 1 );
             ca[4] = 0.0;
             d1 = dvmag( ca, 3 );
             if ( d1 > 0.00000000000001 )d1 = dvmnorm( ca, 3 );
             printf("Twitch\n");
             dvcopy( ca, 4, axis );
             *sphi = d1;
             *cphi = sqrt(1.0 - d1*d1);
             return;
          }
       }
    
       /*   Find angle   */
    
       dgetcolumn(T1, X, ca, 4);
       dgetcolumn(T1, Y, cb, 4);
       dgetcolumn(T2, X, da, 4);
       dgetcolumn(T2, Y, db, 4);
       if( dvdot(axis, 3, cb) > 0.9) { /*  rotation axis is close to j - use  */
          dcross4( axis, ca, cc );      /* change in i axis to find angle  */
          dcross4( axis, da, cd );    
       } 
       else {                          /* use  */
          dcross4( axis, cb, cc );      /* change in j axis to find angle  */
          dcross4( axis, db, cd );    
       }
       d1 = dvmag( cc, 3 );
       d2 = dvmag( cd, 3 );
       /*  fprintf( stdout, "d1, d2:  %11.6lf %11.6lf \n", d1, d2 ); */
       if ( d1 == 0.0 && d2 == 0.0 ) {
          *cphi = 1.0;
          *sphi = 0.0;
       } 
       else {
          dvsmy( cc, 3, 1.0/d1, cc );
          dvsmy( cd, 3, 1.0/d2, cd );   /* normalize */
          *cphi = dvdot(cc, 3, cd);     /* cos(phi) given by dot of two vectors */
          dcross4( cc, cd, dd );
          *sphi = dvmag(dd, 3);
          if( dvdot(dd, 3, axis) < 0.0) {
             *sphi = -(*sphi);
          }
       }
       return;
    }
    
    /* ---------------------------------------------------------------------------- */
    /* Functions to rotate vector or frame about an arbitrary axis */
    
    void RotateVector(double *v, double *axis, double sphi, double cphi, double *y)
    {
       /* v= sin(angle)(axis X v) + Cos(angle)v + (1-Cos(angle))(v . axis) * axis
             See Robots for shearing sheep pg 128 
          Note that v and y can be the same 
       */
    
       double db[6],dd[6];
       double scal;
    
       validate_dvector( db, 1, 4);
       validate_dvector( dd, 1, 4);
       scal = (1.0 - cphi) * dvdot(axis, 3, v);
       dvsmy( axis, 3, scal, dd );  
       dcross4( axis, v, db);
       dvpiv( db, 3, sphi, dd, dd );
       dvpiv( v, 3, cphi, dd, y ); 
       y[4] = 0.0;
    }
    
    void RotateFrame(double **T1, double *axis, double sphi, double cphi,
         double **T2)
    {
       /*  Routine to rotate coord frame T1 about axis by angle phi to give T2
           using quaternion rotation.  Note axis, T1 and T2 are all defined in
           terms of one (world) coord frame - axis is NOT defined in terms of T1.
           It is assumed that T1, and hence T2, are orthogonalized.  T1 can be
           the same array as T2.
           sphi, cphi are sin and cosine of 'phi'.
           Peter Kovesi    May 1985, adapted to C James Trevelyan July 1994
       */
       /*   Temporary local data    */
       double ca[6],cb[6],cc[6],cd[6]; /*   workspace vectors   */
       validate_dvector( ca, 1, 4);
       validate_dvector( cb, 1, 4);
       validate_dvector( cc, 1, 4);
       validate_dvector( cd, 1, 4);
    
    #ifdef V_CHECK
       if ( !valid_dframe( T1 ) )
          nrerror("Invalid 1st frame: RotateFrame\n");
       if ( !valid_dframe( T2 ) )
          nrerror("Invalid 2nd frame: RotateFrame\n");
       if ( !valid_d4vector_b( axis ) )
          nrerror("Invalid axis vector: RotateFrame\n");
    #endif
    
       dgetcolumn( T1, X, ca, 4 );
       RotateVector(ca, axis, sphi, cphi, cb);
       dgetcolumn( T1, Y, ca, 4 );
       RotateVector(ca, axis, sphi, cphi, cc);
       dcross4( cb, cc, cd); /* T2's k axis */
       dputcolumn( cb, 4, T2, X );
       dputcolumn( cc, 4, T2, Y );
       dputcolumn( cd, 4, T2, Z );
       dgetcolumn( T1, U, ca, 4 );
       dputcolumn( ca, 4, T2, U );
    }