changeset 965:e45da450069e

*** empty log message ***
author david <david>
date Wed, 29 Nov 1995 21:36:41 +0000
parents f2a6cd8b7c62
children 8d48efb30e6f
files volume_io/Volumes/evaluate.c
diffstat 1 files changed, 1003 insertions(+), 444 deletions(-) [+]
line wrap: on
line diff
--- a/volume_io/Volumes/evaluate.c
+++ b/volume_io/Volumes/evaluate.c
@@ -15,450 +15,9 @@
 #include  <internal_volume_io.h>
 
 #ifndef lint
-static char rcsid[] = "$Header: /private-cvsroot/minc/volume_io/Volumes/evaluate.c,v 1.25 1995-11-20 12:37:58 david Exp $";
+static char rcsid[] = "$Header: /private-cvsroot/minc/volume_io/Volumes/evaluate.c,v 1.26 1995-11-29 21:36:41 david Exp $";
 #endif
 
-/*--- invalid get voxel functions */
-
-#define  INVALID_GET_FUNC_BODY \
-    { \
-        print_error( "Invalid get voxel function.\n" ); \
-        return( 0 ); \
-    }
-
-/* ARGSUSED */
-
-private  Real  invalid_get_voxel_1d(
-    Volume  volume,
-    int     v0 )
-{
-    INVALID_GET_FUNC_BODY
-}
-
-/* ARGSUSED */
-
-private  Real  invalid_get_voxel_2d(
-    Volume  volume,
-    int     v0,
-    int     v1 )
-{
-    INVALID_GET_FUNC_BODY
-}
-
-/* ARGSUSED */
-
-private  Real  invalid_get_voxel_3d(
-    Volume  volume,
-    int     v0,
-    int     v1,
-    int     v2 )
-{
-    INVALID_GET_FUNC_BODY
-}
-
-/* ARGSUSED */
-
-private  Real  invalid_get_voxel_4d(
-    Volume  volume,
-    int     v0,
-    int     v1,
-    int     v2,
-    int     v3 )
-{
-    INVALID_GET_FUNC_BODY
-}
-
-/* ARGSUSED */
-
-private  Real  invalid_get_voxel_5d(
-    Volume  volume,
-    int     v0,
-    int     v1,
-    int     v2,
-    int     v3,
-    int     v4 )
-{
-    INVALID_GET_FUNC_BODY
-}
-
-/*--- invalid set voxel functions */
-
-#define  INVALID_SET_FUNC_BODY \
-    { \
-        print_error( "Invalid set voxel function.\n" ); \
-    }
-
-/* ARGSUSED */
-
-private  void  invalid_set_voxel_1d(
-    Volume  volume,
-    int     v0,
-    Real    value )
-{
-    INVALID_SET_FUNC_BODY
-}
-
-/* ARGSUSED */
-
-private  void  invalid_set_voxel_2d(
-    Volume  volume,
-    int     v0,
-    int     v1,
-    Real    value )
-{
-    INVALID_SET_FUNC_BODY
-}
-
-/* ARGSUSED */
-
-private  void  invalid_set_voxel_3d(
-    Volume  volume,
-    int     v0,
-    int     v1,
-    int     v2,
-    Real    value )
-{
-    INVALID_SET_FUNC_BODY
-}
-
-/* ARGSUSED */
-
-private  void  invalid_set_voxel_4d(
-    Volume  volume,
-    int     v0,
-    int     v1,
-    int     v2,
-    int     v3,
-    Real    value )
-{
-    INVALID_SET_FUNC_BODY
-}
-
-/* ARGSUSED */
-
-private  void  invalid_set_voxel_5d(
-    Volume  volume,
-    int     v0,
-    int     v1,
-    int     v2,
-    int     v3,
-    int     v4,
-    Real    value )
-{
-    INVALID_SET_FUNC_BODY
-}
-
-private  void  initialize_volume_functions(
-    Volume   volume )
-{
-    volume->get_1d = invalid_get_voxel_1d;
-    volume->get_2d = invalid_get_voxel_2d;
-    volume->get_3d = invalid_get_voxel_3d;
-    volume->get_4d = invalid_get_voxel_4d;
-    volume->get_5d = invalid_get_voxel_5d;
-    volume->get = invalid_get_voxel_5d;
-
-    volume->set_1d = invalid_set_voxel_1d;
-    volume->set_2d = invalid_set_voxel_2d;
-    volume->set_3d = invalid_set_voxel_3d;
-    volume->set_4d = invalid_set_voxel_4d;
-    volume->set_5d = invalid_set_voxel_5d;
-    volume->set = invalid_set_voxel_5d;
-}
-
-#define  FUNCS_1D( type_name, type ) \
-    private   Real  GLUE3(get_,type_name,_1d)( \
-        Volume  volume, \
-        int     v0 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_1D( (volume)->array, type, v0 ) ); \
-    } \
-    private   void  GLUE3(set_,type_name,_1d)( \
-        Volume  volume, \
-        int     v0, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_1D( (volume)->array, type, v0, value ); \
-    } \
-    /* ARGSUSED */ \
-    private   Real  GLUE3(get_,type_name,_1d_5)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_1D( (volume)->array, type, v0 ) ); \
-    } \
-    /* ARGSUSED */ \
-    private   void  GLUE3(set_,type_name,_1d_5)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_1D( (volume)->array, type, v0, value ); \
-    }
-
-#define  FUNCS_2D( type_name, type ) \
-    private   Real  GLUE3(get_,type_name,_2d)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_2D( (volume)->array, type, v0, v1 ) ); \
-    } \
-    private   void  GLUE3(set_,type_name,_2d)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_2D( (volume)->array, type, v0, v1, value ); \
-    } \
-    /* ARGSUSED */ \
-    private   Real  GLUE3(get_,type_name,_2d_5)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_2D( (volume)->array, type, v0,v1 ) ); \
-    } \
-    /* ARGSUSED */ \
-    private   void  GLUE3(set_,type_name,_2d_5)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_2D( (volume)->array, type, v0,v1, value ); \
-    }
-
-
-#define  FUNCS_3D( type_name, type ) \
-    private   Real  GLUE3(get_,type_name,_3d)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_3D( (volume)->array, type, v0, v1, v2 ) ); \
-    } \
-    private   void  GLUE3(set_,type_name,_3d)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_3D( (volume)->array, type, v0, v1, v2, value ); \
-    } \
-    /* ARGSUSED */ \
-    private   Real  GLUE3(get_,type_name,_3d_5)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_3D( (volume)->array, type, v0,v1,v2 ) ); \
-    } \
-    /* ARGSUSED */ \
-    private   void  GLUE3(set_,type_name,_3d_5)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_3D( (volume)->array, type, v0,v1,v2, value ); \
-    }
-
-
-#define  FUNCS_4D( type_name, type ) \
-    private   Real  GLUE3(get_,type_name,_4d)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_4D( (volume)->array, type, v0,v1,v2,v3 ) ); \
-    } \
-    private   void  GLUE3(set_,type_name,_4d)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_4D( (volume)->array, type, v0, v1, v2, v3, value );\
-    } \
-    /* ARGSUSED */ \
-    private   Real  GLUE3(get_,type_name,_4d_5)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_4D( (volume)->array, type, v0,v1,v2,v3 ) ); \
-    } \
-    /* ARGSUSED */ \
-    private   void  GLUE3(set_,type_name,_4d_5)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_4D( (volume)->array, type, v0,v1,v2,v3, value ); \
-    }
-
-
-#define  FUNCS_5D( type_name, type ) \
-    private   Real  GLUE3(get_,type_name,_5d)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4 ) \
-    { \
-        return( GET_MULTIDIM_TYPE_5D( (volume)->array, type, v0,v1,v2,v3,v4 ));\
-    } \
-    private   void  GLUE3(set_,type_name,_5d)( \
-        Volume  volume, \
-        int     v0, \
-        int     v1, \
-        int     v2, \
-        int     v3, \
-        int     v4, \
-        Real    value ) \
-    { \
-        SET_MULTIDIM_TYPE_5D( (volume)->array, type, v0,v1,v2,v3,v4, value );\
-    }
-
-#define FUNCS_TYPE( type_name, type ) \
-     FUNCS_1D( type_name, type ) \
-     FUNCS_2D( type_name, type ) \
-     FUNCS_3D( type_name, type ) \
-     FUNCS_4D( type_name, type ) \
-     FUNCS_5D( type_name, type )
-
-FUNCS_TYPE( unsigned_byte, unsigned char )
-FUNCS_TYPE( signed_byte, signed char )
-FUNCS_TYPE( unsigned_short, unsigned short )
-FUNCS_TYPE( signed_short, signed short )
-FUNCS_TYPE( unsigned_long, unsigned long )
-FUNCS_TYPE( signed_long, signed long )
-FUNCS_TYPE( float, float )
-FUNCS_TYPE( double, double )
-
-#define  INSTALL_FUNCTIONS( volume, type_name, n_dims ) \
-     { \
-         switch( n_dims ) \
-         { \
-         case 1: \
-             (volume)->get_1d = GLUE3(get_,type_name,_1d); \
-             (volume)->get = GLUE3(get_,type_name,_1d_5); \
-             (volume)->set_1d = GLUE3(set_,type_name,_1d); \
-             (volume)->set = GLUE3(set_,type_name,_1d_5); \
-             break; \
-         case 2: \
-             (volume)->get_2d = GLUE3(get_,type_name,_2d); \
-             (volume)->get = GLUE3(get_,type_name,_2d_5); \
-             (volume)->set_2d = GLUE3(set_,type_name,_2d); \
-             (volume)->set = GLUE3(set_,type_name,_2d_5); \
-             break; \
-         case 3: \
-             (volume)->get_3d = GLUE3(get_,type_name,_3d); \
-             (volume)->get = GLUE3(get_,type_name,_3d_5); \
-             (volume)->set_3d = GLUE3(set_,type_name,_3d); \
-             (volume)->set = GLUE3(set_,type_name,_3d_5); \
-             break; \
-         case 4: \
-             (volume)->get_4d = GLUE3(get_,type_name,_4d); \
-             (volume)->get = GLUE3(get_,type_name,_4d_5); \
-             (volume)->set_4d = GLUE3(set_,type_name,_4d); \
-             (volume)->set = GLUE3(set_,type_name,_4d_5); \
-             break; \
-         case 5: \
-             (volume)->get_5d = GLUE3(get_,type_name,_5d); \
-             (volume)->get = GLUE3(get_,type_name,_5d); \
-             (volume)->set_5d = GLUE3(set_,type_name,_5d); \
-             (volume)->set = GLUE3(set_,type_name,_5d); \
-             break; \
-         } \
-     }
-
-private  void   set_volume_array_functions(
-    Volume   volume )
-{
-    int   n_dims;
-
-    n_dims = get_volume_n_dimensions( volume );
-
-    switch( get_volume_data_type(volume) )
-    {
-    case UNSIGNED_BYTE:
-        INSTALL_FUNCTIONS( volume, unsigned_byte, n_dims )
-        break;
-    case SIGNED_BYTE:
-        INSTALL_FUNCTIONS( volume, signed_byte, n_dims )
-        break;
-    case UNSIGNED_SHORT:
-        INSTALL_FUNCTIONS( volume, unsigned_short, n_dims )
-        break;
-    case SIGNED_SHORT:
-        INSTALL_FUNCTIONS( volume, signed_short, n_dims )
-        break;
-    case UNSIGNED_LONG:
-        INSTALL_FUNCTIONS( volume, unsigned_long, n_dims )
-        break;
-    case SIGNED_LONG:
-        INSTALL_FUNCTIONS( volume, signed_long, n_dims )
-        break;
-    case FLOAT:
-        INSTALL_FUNCTIONS( volume, float, n_dims )
-        break;
-    case DOUBLE:
-        INSTALL_FUNCTIONS( volume, double, n_dims )
-        break;
-    }
-}
-
-public  void   set_volume_functions(
-    Volume   volume )
-{
-    initialize_volume_functions( volume );
-
-    if( !volume_is_alloced( volume ) )
-        return;
-
-    if( !volume->is_cached_volume )
-        set_volume_array_functions( volume );
-    else
-        set_volume_cache_functions( volume );
-}
-
 /* ----------------------------- MNI Header -----------------------------------
 @NAME       : convert_voxel_to_value
 @INPUT      : volume
@@ -477,7 +36,11 @@
     Volume   volume,
     Real     voxel )
 {
-    return( CONVERT_VOXEL_TO_VALUE( volume, voxel ) );
+    if( volume->real_range_set )
+        return( volume->real_value_scale * voxel +
+                volume->real_value_translation );
+    else
+        return( voxel );
 }
 
 /* ----------------------------- MNI Header -----------------------------------
@@ -498,5 +61,1001 @@
     Volume   volume,
     Real     value )
 {
-    return( CONVERT_VALUE_TO_VOXEL( volume, value ) );
+    if( volume->real_range_set )
+        return( (value - volume->real_value_translation) /
+                volume->real_value_scale );
+    else
+        return( value );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_volume_voxel_value
+@INPUT      : volume
+              v0          voxel indices
+              v1
+              v2
+              v3
+              v4
+@OUTPUT     : 
+@RETURNS    : Voxel value
+@DESCRIPTION: Returns the voxel at the specified voxel index.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : Mar. 20, 1995    David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Real  get_volume_voxel_value(
+    Volume   volume,
+    int      v0,
+    int      v1,
+    int      v2,
+    int      v3,
+    int      v4 )
+{
+    Real   voxel;
+
+    GET_VOXEL( voxel, volume, v0, v1, v2, v3, v4 );
+
+    return( voxel );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_volume_real_value
+@INPUT      : volume
+              v0          voxel indices
+              v1
+              v2
+              v3
+              v4
+@OUTPUT     : 
+@RETURNS    : Real value
+@DESCRIPTION: Returns the volume real value at the specified voxel index.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : Mar. 20, 1995    David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Real  get_volume_real_value(
+    Volume   volume,
+    int      v0,
+    int      v1,
+    int      v2,
+    int      v3,
+    int      v4 )
+{
+    Real   voxel, value;
+
+    voxel = get_volume_voxel_value( volume, v0, v1, v2, v3, v4 );
+
+    value = convert_voxel_to_value( volume, voxel );
+
+    return( value );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : set_volume_voxel_value
+@INPUT      : volume
+              v0          voxel indices
+              v1
+              v2
+              v3
+              v4
+              voxel
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Sets the voxel at the specified voxel index.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : Mar. 20, 1995    David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  set_volume_voxel_value(
+    Volume   volume,
+    int      v0,
+    int      v1,
+    int      v2,
+    int      v3,
+    int      v4,
+    Real     voxel )
+{
+    SET_VOXEL( volume, v0, v1, v2, v3, v4, voxel );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : set_volume_real_value
+@INPUT      : volume
+              v0          voxel indices
+              v1
+              v2
+              v3
+              v4
+              value
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Sets the volume real value at the specified voxel index.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : Mar. 20, 1995    David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  set_volume_real_value(
+    Volume   volume,
+    int      v0,
+    int      v1,
+    int      v2,
+    int      v3,
+    int      v4,
+    Real     value )
+{
+    Real         voxel;
+    Data_types   data_type;
+
+    voxel = convert_value_to_voxel( volume, value );
+
+    data_type = get_volume_data_type( volume );
+
+    if( data_type != FLOAT &&
+        data_type != DOUBLE )
+    {
+        voxel = ROUND( voxel );
+    }
+
+    set_volume_voxel_value( volume, v0, v1, v2, v3, v4, voxel );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : trilinear_interpolate
+@INPUT      : u              0 to 1 pos
+              v              0 to 1 pos
+              w              0 to 1 pos
+              coefs          8 coeficients
+@OUTPUT     : value    
+              derivs
+@RETURNS    : 
+@DESCRIPTION: Computes the trilinear interpolation of the 8 coeficients, passing
+              the value back in the 'value' parameter.  If the derivs parameter
+              is not null, then the 3 derivatives are also computed and
+              passed back.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : Mar. 20, 1995    David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void    trilinear_interpolate(
+    Real     u,
+    Real     v,
+    Real     w,
+    Real     coefs[],
+    Real     *value,
+    Real     derivs[] )
+{
+    Real   du00, du01, du10, du11, c00, c01, c10, c11, c0, c1, du0, du1;
+    Real   dv0, dv1, dw;
+
+    /*--- get the 4 differences in the u direction */
+
+    du00 = coefs[4] - coefs[0];
+    du01 = coefs[5] - coefs[1];
+    du10 = coefs[6] - coefs[2];
+    du11 = coefs[7] - coefs[3];
+
+    /*--- reduce to a 2D problem, by interpolating in the u direction */
+
+    c00 = coefs[0] + u * du00;
+    c01 = coefs[1] + u * du01;
+    c10 = coefs[2] + u * du10;
+    c11 = coefs[3] + u * du11;
+
+    /*--- get the 2 differences in the v direction for the 2D problem */
+
+    dv0 = c10 - c00;
+    dv1 = c11 - c01;
+
+    /*--- reduce 2D to a 1D problem, by interpolating in the v direction */
+
+    c0 = c00 + v * dv0;
+    c1 = c01 + v * dv1;
+
+    /*--- get the 1 difference in the w direction for the 1D problem */
+
+    dw = c1 - c0;
+
+    /*--- if the value is desired, interpolate in 1D to get the value */
+
+    if( value != NULL )
+        *value = c0 + w * dw;
+
+    /*--- if the derivatives are desired, compute them */
+
+    if( derivs != NULL )
+    {
+        /*--- reduce the 2D u derivs to 1D */
+
+        du0 = INTERPOLATE( v, du00, du10 );
+        du1 = INTERPOLATE( v, du01, du11 );
+
+        /*--- interpolate the 1D problems in w, or for Z deriv, just use dw */
+
+        derivs[X] = INTERPOLATE( w, du0, du1 );
+        derivs[Y] = INTERPOLATE( w, dv0, dv1 );
+        derivs[Z] = dw;
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : interpolate_volume
+@INPUT      : n_dims        - number of dimensions to interpolate
+              parameters[]  - 0 to 1 parameters for each dim
+              n_values      - number of values to interpolate
+              degree        - degree of interpolation, 4 == cubic
+              coefs         - [degree*degree*degree... *n_values] coeficients
+@OUTPUT     : values        - pass back values
+              first_deriv   - pass first derivs [n_values][n_dims]
+              second_deriv  - pass back values  [n_values][n_dims][n_dims]
+@RETURNS    : 
+@DESCRIPTION: Computes the interpolation of the box specified by coefs and
+              its derivatives, if necessary.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : Mar. 20, 1995    David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+#define  MAX_DERIV_SIZE  100
+
+private  void   interpolate_volume(
+    int      n_dims,
+    Real     parameters[],
+    int      n_values,
+    int      degree,
+    Real     coefs[],
+    Real     values[],
+    Real     **first_deriv,
+    Real     ***second_deriv )
+{
+    int       v, d, d2, n_derivs, derivs_per_value, mult, mult2;
+    Real      fixed_size_derivs[MAX_DERIV_SIZE];
+    Real      *derivs;
+
+    /*--- determine how many derivatives should be computed */
+
+    if( second_deriv != NULL )
+        n_derivs = 2;
+    else if( first_deriv != NULL )
+        n_derivs = 1;
+    else
+        n_derivs = 0;
+
+    /*--- compute the total number of values, 1st and 2nd derivatives per val*/
+
+    derivs_per_value = 1;
+    for_less( d, 0, n_dims )
+        derivs_per_value *= 1 + n_derivs;
+
+    /*--- make storage for the spline routines to place the answers */
+
+    if( n_values * derivs_per_value <= MAX_DERIV_SIZE )
+    {
+        derivs = fixed_size_derivs;
+    }
+    else
+    {
+        ALLOC( derivs, n_values * derivs_per_value );
+    }
+
+    /*--- evaluate the interpolating spline */
+
+    evaluate_interpolating_spline( n_dims, parameters, degree, n_values, coefs,
+                                   n_derivs, derivs );
+
+    /*--- derivs is now a one dimensional array representing
+          derivs[n_values][1+n_derivs][1+n_derivs]...,
+          where derivs[0][0][0][0]... = the interpolated value for 1st comp,
+                derivs[1][0][0][0]... = the interpolated value for 2nd comp,
+                derivs[n_values-1][0][0][0]... = interpolated value for last,
+                derivs[0][1][0][0]... = derivative of 1st comp wrt x
+                derivs[0][0][1][0]... = derivative of 1st comp wrt y
+                derivs[1][1][0][0]... = derivative of 2nd comp wrt x, etc. */
+
+    if( values != NULL )
+    {
+        for_less( v, 0, n_values )
+            values[v] = derivs[v*derivs_per_value];
+    }
+
+    /*--- fill in the first derivatives, if required */
+
+    if( first_deriv != NULL )
+    {
+        mult = 1;
+        for_down( d, n_dims-1, 0 )
+        {
+            for_less( v, 0, n_values )
+                first_deriv[v][d] = derivs[mult + v*derivs_per_value];
+
+            mult *= 1 + n_derivs;
+        }
+    }
+
+    /*--- fill in the second derivatives, if required */
+
+    if( second_deriv != NULL )
+    {
+        mult = 1;
+        for_down( d, n_dims-1, 0 )
+        {
+            for_less( v, 0, n_values )
+                second_deriv[v][d][d] = derivs[2*mult + v*derivs_per_value];
+
+            mult *= 1 + n_derivs;
+        }
+
+        mult = 1;
+        for_down( d, n_dims-1, 0 )
+        {
+            mult2 = 1;
+
+            for_down( d2, n_dims-1, d+1 )
+            {
+                for_less( v, 0, n_values )
+                {
+                    second_deriv[v][d][d2] =
+                           derivs[mult+mult2+v*derivs_per_value];
+                    second_deriv[v][d2][d] =
+                           derivs[mult+mult2+v*derivs_per_value];
+                }
+
+                mult2 *= 1 + n_derivs;
+            }
+
+            mult *= 1 + n_derivs;
+        }
+    }
+
+    if( n_values * derivs_per_value > MAX_DERIV_SIZE )
+    {
+        FREE( derivs );
+    }
 }
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : extract_coefficients
+@INPUT      : volume
+              start
+              end
+              inc
+@OUTPUT     : coefs
+@RETURNS    : 
+@DESCRIPTION: Extracts the coefficients from a volume.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : Jun 21, 1995    David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void   extract_coefficients(
+    Volume         volume,
+    int            start[],
+    int            end[],
+    Real           coefs[],
+    int            inc[] )
+{
+    int      inc0, inc1, inc2, inc3, inc4;
+    int      ind;
+    int      start0, start1, start2, start3, start4;
+    int      end0, end1, end2, end3, end4, n_dims;
+    int      v0, v1, v2, v3, v4;
+
+    /*--- for speed, use non-array variables for the loops */
+
+    start0 = start[0];
+    start1 = start[1];
+    start2 = start[2];
+    start3 = start[3];
+    start4 = start[4];
+
+    end0 = end[0];
+    end1 = end[1];
+    end2 = end[2];
+    end3 = end[3];
+    end4 = end[4];
+
+    inc0 = inc[0];
+    inc1 = inc[1];
+    inc2 = inc[2];
+    inc3 = inc[3];
+    inc4 = inc[4];
+
+    /*--- adjust the inc stride for stepping through coefs to account
+          for the additions of the inner loops */
+
+    n_dims = get_volume_n_dimensions(volume);
+
+    if( n_dims >= 2 )
+        inc0 -= inc1 * (end1 - start1);
+    if( n_dims >= 3 )
+        inc1 -= inc2 * (end2 - start2);
+    if( n_dims >= 4 )
+        inc2 -= inc3 * (end3 - start3);
+    if( n_dims >= 5 )
+        inc3 -= inc4 * (end4 - start4);
+
+    /*--- get the coefs[] from the volume.  For speed, do each dimension
+          separately */
+
+    ind = 0;
+
+    switch( n_dims )
+    {
+    case 1:
+        for_less( v0, start0, end0 )
+        {
+            GET_VALUE_1D( coefs[ind], volume, v0 );
+            ind += inc0;
+        }
+        break;
+
+    case 2:
+        for_less( v0, start0, end0 )
+        {
+            for_less( v1, start1, end1 )
+            {
+                GET_VALUE_2D( coefs[ind], volume, v0, v1 );
+                ind += inc1;
+            }
+            ind += inc0;
+        }
+        break;
+
+    case 3:
+        for_less( v0, start0, end0 )
+        {
+            for_less( v1, start1, end1 )
+            {
+                for_less( v2, start2, end2 )
+                {
+                    GET_VALUE_3D( coefs[ind], volume, v0, v1, v2 );
+                    ind += inc2;
+                }
+                ind += inc1;
+            }
+            ind += inc0;
+        }
+        break;
+
+    case 4:
+        for_less( v0, start0, end0 )
+        {
+            for_less( v1, start1, end1 )
+            {
+                for_less( v2, start2, end2 )
+                {
+                    for_less( v3, start3, end3 )
+                    {
+                        GET_VALUE_4D( coefs[ind], volume, v0, v1, v2, v3 );
+                        ind += inc3;
+                    }
+                    ind += inc2;
+                }
+                ind += inc1;
+            }
+            ind += inc0;
+        }
+        break;
+
+    case 5:
+        for_less( v0, start0, end0 )
+        {
+            for_less( v1, start1, end1 )
+            {
+                for_less( v2, start2, end2 )
+                {
+                    for_less( v3, start3, end3 )
+                    {
+                        for_less( v4, start4, end4 )
+                        {
+                            GET_VALUE_5D( coefs[ind], volume,
+                                          v0, v1, v2, v3, v4 );
+                            ind += inc4;
+                        }
+                        ind += inc3;
+                    }
+                    ind += inc2;
+                }
+                ind += inc1;
+            }
+            ind += inc0;
+        }
+        break;
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : evaluate_volume
+@INPUT      : volume
+              voxel
+              interpolating_dimensions - whether each dimension is interpolated
+              degrees_continuity
+              use_linear_at_edge
+              outside_value
+@OUTPUT     : values
+              first_deriv
+              second_deriv
+@RETURNS    : 
+@DESCRIPTION: Takes a voxel space position and evaluates the value within
+              the volume by nearest_neighbour, linear, quadratic, or
+              cubic interpolation. degrees_continuity == 2 corresponds to
+              cubic, 1 for quadratic, etc.
+              If first_deriv is not a null pointer, then the first derivatives
+              are passed back.  Similarly for the second_deriv.
+              If use_linear_at_edge is TRUE, then near the boundaries, either
+              linear or nearest neighbour interpolation is used, even if cubic
+              is specified by the degrees_continuity.
+              If use_linear_at_edge is FALSE, then the 'outside_value' is used
+              to provide coefficients for outside the volume, and the degree
+              specified by degrees_continuity is used.
+
+              Each dimension may or may not be interpolated, specified by the
+              interpolating_dimensions parameter.  For instance, a 4D volume
+              of x,y,z,RGB may be interpolated in 3D (x,y,z) for each of the
+              3 RGB components, with one call to evaluate_volume.
+@CREATED    : Mar   1993           David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+#define MAX_COEF_SPACE   1000
+
+public  int   evaluate_volume(
+    Volume         volume,
+    Real           voxel[],
+    BOOLEAN        interpolating_dimensions[],
+    int            degrees_continuity,
+    BOOLEAN        use_linear_at_edge,
+    Real           outside_value,
+    Real           values[],
+    Real           **first_deriv,
+    Real           ***second_deriv )
+{
+    int      inc[MAX_DIMENSIONS];
+    int      start_index, spline_degree;
+    int      next_d;
+    int      n, v, d, dim, n_values, sizes[MAX_DIMENSIONS], n_dims;
+    int      start[MAX_DIMENSIONS], n_interp_dims;
+    int      end[MAX_DIMENSIONS];
+    int      interp_dims[MAX_DIMENSIONS];
+    int      n_coefs;
+    Real     fraction[MAX_DIMENSIONS], bound, *coefs, pos;
+    Real     fixed_size_coefs[MAX_COEF_SPACE];
+    BOOLEAN  fully_inside, fully_outside;
+
+    /*--- check if the degrees continuity is between nearest neighbour
+          and cubic */
+
+    if( degrees_continuity < -1 || degrees_continuity > 2 )
+    {
+        print_error( "Warning: evaluate_volume(), degrees invalid: %d\n",
+                     degrees_continuity );
+        degrees_continuity = 0;
+    }
+
+    n_dims = get_volume_n_dimensions(volume);
+    get_volume_sizes( volume, sizes );
+
+    bound = (Real) degrees_continuity / 2.0;
+
+    /*--- if we must use linear interpolation near the boundaries, then
+          check if we are near the boundaries, and adjust the degrees_continuity
+          accordingly */
+
+    if( use_linear_at_edge && degrees_continuity >= 0 )
+    {
+        for_less( d, 0, n_dims )
+        {
+            if( interpolating_dimensions == NULL || interpolating_dimensions[d])
+            {
+                while( degrees_continuity >= 0 &&
+                       (voxel[d] < bound  ||
+                        voxel[d] > (Real) sizes[d] - 1.0 - bound  ||
+                        bound == (Real) sizes[d] - 1.0 - bound ) )
+                {
+                    --degrees_continuity;
+                    if( degrees_continuity == 1 )
+                        degrees_continuity = 0;
+                    bound = (Real) degrees_continuity / 2.0;
+                }
+            }
+        }
+    }
+
+    /*--- now check which dimensions are being interpolated.  Also, compute
+          how many values must be interpolated, which are all the values not
+          in the interpolated dimensions */
+
+    n_interp_dims = 0;
+    n_values = 1;
+    n_coefs = 1;
+    spline_degree = degrees_continuity + 2;
+
+    fully_inside = TRUE;
+    fully_outside = FALSE;
+
+    for_less( d, 0, n_dims )
+    {
+        if( interpolating_dimensions == NULL || interpolating_dimensions[d])
+        {
+            interp_dims[n_interp_dims] = d;
+            pos = voxel[d] - bound;
+            start[d] =       FLOOR( pos );
+            fraction[n_interp_dims] = pos - start[d];
+
+            if( voxel[d] == (Real) sizes[d] - 1.0 - bound )
+            {
+                --start[d];
+                fraction[n_interp_dims] = 1.0;
+            }
+
+            end[d] = start[d] + spline_degree;
+            n_coefs *= spline_degree;
+
+            if( start[d] < 0 || end[d] > sizes[d] )
+            {
+                fully_inside = FALSE;
+
+                if( end[d] <= 0 || start[d] >= sizes[d] )
+                {
+                    fully_outside = TRUE;
+                    break;
+                }
+            }
+
+            ++n_interp_dims;
+        }
+        else
+            n_values *= sizes[d];
+    }
+
+    /*--- check if the first derivatives are uncomputable */
+
+    if( first_deriv != NULL && (fully_outside || degrees_continuity < 0) )
+    {
+        for_less( v, 0, n_values )
+            for_less( d, 0, n_interp_dims )
+                first_deriv[v][d] = 0.0;
+    }
+
+    /*--- check if the second derivatives are uncomputable */
+
+    if( second_deriv != NULL && (fully_outside || degrees_continuity < 1) )
+    {
+        for_less( v, 0, n_values )
+            for_less( d, 0, n_interp_dims )
+                for_less( dim, 0, n_interp_dims )
+                   second_deriv[v][d][dim] = 0.0;
+    }
+
+    /*--- check if the values are uncomputable, i.e., outside volume */
+
+    if( fully_outside )
+    {
+        if( values != NULL )
+        {
+            for_less( v, 0, n_values )
+                values[v] = outside_value;
+        }
+
+        return( n_values );
+    }
+
+    /*--- add the non-interpolated dimensions to the list of dimensions, in
+          order, after the interpolated dimensions */
+
+    n = 0;
+    for_less( d, 0, n_dims )
+    {
+        if( interpolating_dimensions != NULL && !interpolating_dimensions[d] )
+        {
+            interp_dims[n_interp_dims+n] = d;
+            start[d] = 0;
+            end[d] = sizes[d];
+            ++n;
+        }
+    }
+
+    /*--- make room for the coeficients */
+
+    if( n_values * n_coefs > MAX_COEF_SPACE )
+    {
+        ALLOC( coefs, n_values * n_coefs );
+    }
+    else
+        coefs = fixed_size_coefs;
+
+    /*--- compute the increments in the coefs[] array for each dimension,
+          in order to simulate a multidimensional array with a single dim
+          array, coefs */
+
+    inc[interp_dims[n_dims-1]] = 1;
+    for_down( d, n_dims-2, 0 )
+    {
+        next_d = interp_dims[d+1];
+        inc[interp_dims[d]] = inc[next_d] * (end[next_d] - start[next_d]);
+    }
+
+    /*--- figure out the offset within coefs.  If we are inside, the offset
+          is zero, since all coefs must be filled in.  If we are partially
+          inside, set the offset to the first coef within the volume. */
+
+    start_index = 0;
+
+    if( !fully_inside )
+    {
+        for_less( d, 0, n_dims )
+        {
+            if( start[d] < 0 )
+            {
+                start_index += -start[d] * inc[d];
+                start[d] = 0;
+            }
+
+            if( end[d] > sizes[d] )
+                end[d] = sizes[d];
+        }
+
+        for_less( v, 0, n_values * n_coefs )
+            coefs[v] = outside_value;
+    }
+
+    /*--- get the necessary coeficients from the volume */
+
+    extract_coefficients( volume, start, end, &coefs[start_index], inc );
+
+    /*--- now that we have the coeficients, do the interpolation */
+
+    switch( degrees_continuity )
+    {
+    case -1:                        /*--- nearest neighbour interpolation */
+        for_less( v, 0, n_values )
+            values[v] = coefs[v];
+        break;
+
+    case 0:
+    case 1:
+    case 2:
+        /*--- check for the common case trilinear interpolation of 1 value */
+
+        if( degrees_continuity == 0 && n_interp_dims == 3 && n_values == 1 )
+        {
+            Real   *deriv;
+
+            if( first_deriv == NULL )
+                deriv = NULL;
+            else
+                deriv = first_deriv[0];
+
+            trilinear_interpolate( fraction[0], fraction[1], fraction[2],
+                                   coefs, values, deriv );
+        }
+        else
+        {
+            interpolate_volume( n_interp_dims, fraction, n_values,
+                                spline_degree, coefs,
+                                values, first_deriv, second_deriv );
+        }
+
+        break;
+    }
+
+    if( n_values * n_coefs > MAX_COEF_SPACE )
+    {
+        FREE( coefs );
+    }
+
+    return( n_values );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : evaluate_volume_in_world
+@INPUT      : volume
+              x
+              y
+              z
+              degrees_continuity - 0 = linear, 2 = cubic
+              use_linear_at_edge
+              outside_value
+@OUTPUT     : values
+              deriv_x
+              deriv_y
+              deriv_z
+              deriv_xx
+              deriv_xy
+              deriv_xz
+              deriv_yy
+              deriv_yz
+              deriv_zz
+@RETURNS    : 
+@DESCRIPTION: Takes a world space position and evaluates the value within
+              the volume.
+              If deriv_x is not a null pointer, then the 3 derivatives are
+              passed back.  If deriv_xx is not null, then the 6 second
+              derivatives are passed back.  If the volume is 3D, then only
+              one value, and one derivative per deriv_x,etc. is passed back.
+              If the volume has more than 3 dimensions, say 5 dimensions, with
+              dimensions 3 and 4 being the non-spatial dimensions, then there
+              will be sizes[3] * sizes[4] values passed back.  The derivatives
+              are converted to world space.
+@CREATED    : Mar   1993           David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void   evaluate_volume_in_world(
+    Volume         volume,
+    Real           x,
+    Real           y,
+    Real           z,
+    int            degrees_continuity,
+    BOOLEAN        use_linear_at_edge,
+    Real           outside_value,
+    Real           values[],
+    Real           deriv_x[],
+    Real           deriv_y[],
+    Real           deriv_z[],
+    Real           deriv_xx[],
+    Real           deriv_xy[],
+    Real           deriv_xz[],
+    Real           deriv_yy[],
+    Real           deriv_yz[],
+    Real           deriv_zz[] )
+{
+    Real      ignore;
+    Real      voxel[MAX_DIMENSIONS];
+    Real      **first_deriv, ***second_deriv;
+    Real      t[N_DIMENSIONS][MAX_DIMENSIONS];
+    int       c, d, dim, v, n_values, n_dims, axis;
+    int       sizes[MAX_DIMENSIONS], dims_interpolated[N_DIMENSIONS];
+    BOOLEAN   interpolating_dimensions[MAX_DIMENSIONS];
+
+    /*--- convert the world space to a voxel coordinate */
+
+    convert_world_to_voxel( volume, x, y, z, voxel );
+    get_volume_sizes( volume, sizes );
+
+    /*--- initialize all dimensions to not being interpolated */
+
+    n_dims = get_volume_n_dimensions( volume );
+    for_less( d, 0, n_dims )
+        interpolating_dimensions[d] = FALSE;
+
+    /*--- set each spatial dimension to being interpolated */
+
+    for_less( d, 0, N_DIMENSIONS )
+    {
+        axis = volume->spatial_axes[d];
+        if( axis < 0 )
+        {
+            print_error(
+                  "evaluate_volume_in_world(): must have 3 spatial axes.\n" );
+            return;
+        }
+
+        interpolating_dimensions[axis] = TRUE;
+    }
+
+    /*--- compute the number of values, the product of the sizes of the
+          non-interpolating dimensions */
+    
+    n_values = 1;
+    for_less( d, 0, n_dims )
+    {
+        if( !interpolating_dimensions[d] )
+            n_values *= sizes[d];
+    }
+
+    /*--- make room for the first derivative, if necessary */
+
+    if( deriv_x != NULL )
+    {
+        ALLOC2D( first_deriv, n_values, N_DIMENSIONS );
+    }
+    else
+        first_deriv = NULL;
+
+    /*--- make room for the second derivative, if necessary */
+
+    if( deriv_xx != NULL )
+    {
+        ALLOC3D( second_deriv, n_values, N_DIMENSIONS, N_DIMENSIONS );
+    }
+    else
+        second_deriv = NULL;
+
+    /*--- evaluate the volume and derivatives in voxel space */
+
+    n_values = evaluate_volume( volume, voxel, interpolating_dimensions,
+                      degrees_continuity, use_linear_at_edge, outside_value,
+                      values, first_deriv, second_deriv );
+
+    /*--- if the derivative is desired, convert the voxel derivative
+          to world space */
+
+    if( deriv_x != NULL || deriv_xx != NULL )
+    {
+        /*--- figure out the dimensions interpolated, in order */
+
+        dim = 0;
+        for_less( d, 0, n_dims )
+        {
+            if( interpolating_dimensions[d] )
+            {
+                dims_interpolated[dim] = d;
+                ++dim;
+            }
+        }
+    }
+
+    if( deriv_x != NULL )
+    {
+        for_less( v, 0, n_values )    /*--- convert the deriv of each value */
+        {
+            /*--- get the voxel coordinates of the first derivative */
+
+            for_less( c, 0, N_DIMENSIONS )
+                voxel[dims_interpolated[c]] = first_deriv[v][c];
+
+            /*--- convert the voxel-space derivative to a world derivative */
+
+            convert_voxel_normal_vector_to_world( volume, voxel,
+                                   &deriv_x[v], &deriv_y[v], &deriv_z[v] );
+        }
+
+        FREE2D( first_deriv );
+    }
+
+    /*--- if the derivative is desired, convert the voxel derivative
+          to world space */
+
+    if( deriv_xx != (Real *) 0 )
+    {
+        for_less( v, 0, n_values )    /*--- convert the deriv of each value */
+        {
+            /*--- get the voxel coordinates of the first derivative */
+
+            for_less( dim, 0, N_DIMENSIONS )
+            {
+                for_less( c, 0, N_DIMENSIONS )
+                    voxel[dims_interpolated[c]] = second_deriv[v][dim][c];
+
+                /*--- convert the voxel-space derivative to a world derivative*/
+
+                convert_voxel_normal_vector_to_world( volume, voxel,
+                      &t[X][dims_interpolated[dim]],
+                      &t[Y][dims_interpolated[dim]],
+                      &t[Z][dims_interpolated[dim]] );
+            }
+
+            /*--- now convert the results to world */
+    
+            convert_voxel_normal_vector_to_world( volume, t[X],
+                                              &deriv_xx[v], &ignore, &ignore );
+    
+            convert_voxel_normal_vector_to_world( volume, t[Y],
+                                          &deriv_xy[v], &deriv_yy[v], &ignore );
+    
+            convert_voxel_normal_vector_to_world( volume, t[Z],
+                                  &deriv_xz[v], &deriv_yz[v], &deriv_zz[v] );
+        }
+
+        FREE3D( second_deriv );
+    }
+}