changeset 653:5b54f537bd80

check_in_all
author david <david>
date Tue, 01 Nov 1994 14:08:01 +0000
parents 779bc9072500
children 00510a6dcc11
files volume_io/Documentation/volume_io.tex volume_io/Include/volume_io/basic.h volume_io/Include/volume_io/geom_structs.h volume_io/Include/volume_io/volume.h volume_io/MNI_formats/tag_points.c volume_io/Prog_utils/alloc.c volume_io/Prog_utils/files.c volume_io/Prog_utils/progress.c volume_io/Testing/reorder_volume.c volume_io/Volumes/input_mnc.c volume_io/Volumes/input_volume.c volume_io/Volumes/output_mnc.c volume_io/Volumes/output_volume.c volume_io/Volumes/volumes.c
diffstat 14 files changed, 381 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/volume_io/Documentation/volume_io.tex
+++ b/volume_io/Documentation/volume_io.tex
@@ -554,12 +554,8 @@
 the second argument, \name{expanded\_filename}, which must be a
 different string pointer.  Any sequence of
 characters starting with a \name{\~\ } up to but not including a slash,
-\name{/}, will be changed to the current users home directory.  Note
-that this will only work properly if the \name{\~\ } is used alone, or
-in conjunction with the current user's user name.  For example,
-if user \name{john} passes this routine a filename of
-\name{\~\ frank/text}, it will be expanded to \name{/usr/people/john/text},
-which is not what was desired.  Any occurrence of a dollar sign,
+\name{/}, will be changed to the specified users home directory.
+Any occurrence of a dollar sign,
 \name{\$}, will result in the following text, up to the next slash,
 being expanded to the environment variable specified by the text.  This
 expansion can be avoided by placing a backslash, \name{$\backslash$},
@@ -1618,7 +1614,8 @@
 
 Since most volumes will be created by reading from a MINC file, this
 method will be presented first, followed by a description of how to
-create a volume from scratch.
+create a volume from scratch.  Finally a lower level of MINC input and
+output for more advanced applications will be presented.
 
 \section{Volume Input}
 
@@ -2226,6 +2223,133 @@
 \end{verbatim}
 }
 
+\section{Multiple Volume Input}
+
+The \name{input\_volume} function described previously is intended to
+be a simple single-function interface for reading volumes for most
+applications.  Occasionally, however, an application may not want to
+read the whole volume at once, or may need to break the input file
+into several volumes, for instance, the slices of a 3D volume.  This can
+be facilitated by the following functions:
+
+{\bf\begin{verbatim}
+public  Minc_file  initialize_minc_input(
+    char                 filename[],
+    Volume               volume,
+    minc_input_options   *options )
+\end{verbatim}}
+
+\desc{This functions opens a MINC file for input to the specified
+volume.  The number of
+dimensions in the file must be greater than or equal to the number of
+dimensions in the volume, and each dimension name in the volume must
+have a matching dimension name in the file.  A file handle is
+returned, for use in the following routines.}
+
+{\bf\begin{verbatim}
+public  int  get_n_input_volumes(
+    Minc_file  file )
+\end{verbatim}}
+
+\desc{Determines the total number of volumes in the opened MINC file.
+For instance, if the file contains x, y, z data of size 100 by 200 by
+300 and the file was opened with a two dimensional x-z volume, then
+the number of volumes returned will be 200, the number of y slices.}
+
+{\bf\begin{verbatim}
+public  BOOLEAN  input_more_minc_file(
+    Minc_file   file,
+    Real        *fraction_done )
+\end{verbatim}}
+
+\desc{Reads part of the MINC file to the volume specified in
+\name{initialize\_minc\_input}.  This function must be called until it
+returns FALSE, at which point the volume has been fully read in.  In
+order to read the next volume in the file, if any, the following
+function must be called.}
+
+{\bf\begin{verbatim}
+public  BOOLEAN  advance_input_volume(
+    Minc_file   file )
+\end{verbatim}}
+
+\desc{Advances the input file to the next volume.}
+
+{\bf\begin{verbatim}
+public  BOOLEAN  reset_input_volume(
+    Minc_file   file )
+\end{verbatim}}
+
+\desc{Resets the input to the beginning of the first volume in the
+file.}
+
+{\bf\begin{verbatim}
+public  Status  close_minc_input(
+    Minc_file   file )
+\end{verbatim}}
+
+\desc{Closes the MINC file.}
+
+\section{Multiple Volume Output}
+
+Similarly to the multiple volume input, there are routines for
+providing output to a file by subvolumes.
+
+{\bf\begin{verbatim}
+public  Minc_file  initialize_minc_output(
+    char                   filename[],
+    int                    n_dimensions,
+    STRING                 dim_names[],
+    int                    sizes[],
+    nc_type                file_nc_data_type,
+    BOOLEAN                file_signed_flag,
+    Real                   file_voxel_min,
+    Real                   file_voxel_max,
+    Real                   real_min,
+    Real                   real_max,
+    General_transform      *voxel_to_world_transform,
+    minc_output_options    *options )
+\end{verbatim}}
+
+\desc{Opens a MINC file for creation.  The arguments specify the
+number of dimensions and the names of each dimension, as well as the
+sizes in each dimensions.  The type of the file is controlled by the
+four parameters, \name{file\_nc\_data\_type},
+\name{file\_signed\_flag}, \name{file\_voxel\_min}, and
+\name{file\_voxel\_max}.  The mapping of voxels to real values is
+specified by \name{real\_min} and \name{real\_max}.  The
+transformation to world coordinates is specified by the
+\name{voxel\_to\_world\_transform} argument.  The \name{options} are
+as specified for the \name{output\_volume} function.}
+
+{\bf\begin{verbatim}
+public  Status  copy_auxiliary_data_from_minc_file(
+    Minc_file   file,
+    char        filename[],
+    char        history_string[] )
+\end{verbatim}}
+
+\desc{Copies the auxiliary information from the MINC file specified in
+the \name{filename} argument to the open MINC \name{file}.}
+
+{\bf\begin{verbatim}
+public  Status  output_minc_volume(
+    Minc_file   file,
+    Volume      volume )
+\end{verbatim}}
+
+\desc{Outputs a volume to the MINC file.  The volume must have no more
+dimensions than the file and the names of each dimension must match
+with one of the dimensions in the file (specified by
+\name{initialize\_minc\_output}).}
+
+{\bf\begin{verbatim}
+public  Status  close_minc_output(
+    Minc_file   file )
+\end{verbatim}}
+
+\desc{Closes the MINC file.}
+
 \chapter{Tag Points}
 
 Tag points are sets of three dimensional points which are used to mark
--- a/volume_io/Include/volume_io/basic.h
+++ b/volume_io/Include/volume_io/basic.h
@@ -120,9 +120,7 @@
 
 /* --------------- */
 
-#define  ROUND( x )     ((int) ((x) + 0.5))
-
-#define  ROUND_UP( x )     ( (x) < 0.0 ? (int) ((x) - 0.5)      \
+#define  ROUND( x )     ( (x) < 0.0 ? (int) ((x) - 0.5)      \
                                     : (int) ((x) + 0.5) )
 
 #define  IS_INT( x )    ((double) (x) == (double) ((int) (x)))
--- a/volume_io/Include/volume_io/geom_structs.h
+++ b/volume_io/Include/volume_io/geom_structs.h
@@ -64,13 +64,13 @@
 
 #ifdef lint
 #define  make_Colour_0_1( r, g, b ) ((Colour) ( r + g + b ))
-#define  make_Colour_0_1_alpha( r, g, b, a ) ((Colour) ( r + g + b + a))
+#define  make_rgba_Colour_0_1( r, g, b, a ) ((Colour) ( r + g + b + a))
 #else
 #define  make_Colour_0_1( r, g, b )                       \
             make_Colour( COLOUR_0_1_TO_256(r),            \
                          COLOUR_0_1_TO_256(g),            \
                          COLOUR_0_1_TO_256(b) )
-#define  make_Colour_0_1_alpha( r, g, b, a )              \
+#define  make_rgba_Colour_0_1( r, g, b, a )              \
             make_rgba_Colour( COLOUR_0_1_TO_256(r),            \
                               COLOUR_0_1_TO_256(g),            \
                               COLOUR_0_1_TO_256(b),            \
@@ -78,7 +78,7 @@
 #endif
 
 #define  get_Colour_luminance( c )                                            \
-            ROUND( 0.288 * (Real) get_Colour_r(c) +                           \
+            ROUND( 0.299 * (Real) get_Colour_r(c) +                           \
                    0.587 * (Real) get_Colour_g(c) +                           \
                    0.114 * (Real) get_Colour_b(c) )
 
@@ -100,7 +100,7 @@
             r = r1 * r2; \
             g = g1 * g2; \
             b = b1 * b2; \
-            (prod) = make_Colour_0_1_alpha( r, g, b, get_Colour_a_0_1(c1) ); \
+            (prod) = make_rgba_Colour_0_1( r, g, b, get_Colour_a_0_1(c1) ); \
         }
 
 #define  ADD_COLOURS( sum, c1, c2 )                  \
--- a/volume_io/Include/volume_io/volume.h
+++ b/volume_io/Include/volume_io/volume.h
@@ -294,6 +294,7 @@
     int                n_file_dimensions;
     int                sizes_in_file[MAX_VAR_DIMS];
     long               indices[MAX_VAR_DIMS];
+    char               *dim_names[MAX_VAR_DIMS];
 
     /* input only */
 
@@ -302,6 +303,7 @@
     Volume             volume;
 
     int                axis_index_in_file[MAX_VAR_DIMS];
+    int                to_file_index[MAX_DIMENSIONS];
     int                valid_file_axes[MAX_DIMENSIONS];
 
     int                n_slab_dims;
@@ -318,14 +320,13 @@
     BOOLEAN            end_def_done;
     BOOLEAN            variables_written;
     int                dim_ids[MAX_VAR_DIMS];
-    char               *dim_names[MAX_VAR_DIMS];
 } minc_file_struct;
 
 typedef  minc_file_struct  *Minc_file;
 
 typedef  struct
 {
-    int       arent_any_yet;
+    int         arent_any_yet;
 } volume_creation_options;
 
 typedef  struct
@@ -336,7 +337,7 @@
 
 typedef  struct
 {
-    int         duh;
+    STRING   dimension_names[MAX_DIMENSIONS];
 } minc_output_options;
 
 /* recognized file formats */
--- a/volume_io/MNI_formats/tag_points.c
+++ b/volume_io/MNI_formats/tag_points.c
@@ -146,6 +146,9 @@
         (void) fprintf( file, "\n" );
     }
 
+    if( n_tag_points == 0 )
+        (void) fprintf( file, ";\n" );
+
     return( status );
 }
 
--- a/volume_io/Prog_utils/alloc.c
+++ b/volume_io/Prog_utils/alloc.c
@@ -37,7 +37,7 @@
         {
             set_print_function( NULL );
             print( "Error alloc_memory: out of memory, %d bytes.\n", n_bytes );
-            abort_if_allowed();
+            abort();
         }
     }
     else
--- a/volume_io/Prog_utils/files.c
+++ b/volume_io/Prog_utils/files.c
@@ -1,5 +1,6 @@
 
 #include  <volume_io.h>
+#include  <pwd.h>
 
 private  BOOLEAN  has_no_extension( char [] );
 
@@ -99,6 +100,19 @@
     (void) unlink( filename );
 }
 
+private  char  *get_user_home_directory(
+    char   user_name[] )
+{
+    struct   passwd  *p;
+
+    p = getpwnam( user_name );
+
+    if( p == NULL )
+        return( NULL );
+    else
+        return( p->pw_dir );
+}
+
 /* ----------------------------- MNI Header -----------------------------------
 @NAME       : expand_filename
 @INPUT      : filename
@@ -120,8 +134,8 @@
     char  expanded_filename[] )
 {
     int      i, new_i, dest, len, env_index;
-    BOOLEAN  use_home, prev_was_backslash;
-    char     *env_value;
+    BOOLEAN  tilde_found, prev_was_backslash;
+    char     *expand_value;
     STRING   env;
 
     len = strlen( filename );
@@ -135,7 +149,7 @@
             ((i == 0 && filename[i] == '~') || filename[i] == '$') )
         {
             new_i = i;
-            use_home = (filename[new_i] == '~');
+            tilde_found = (filename[new_i] == '~');
             ++new_i;
             env_index = 0;
             while( filename[new_i] != '/' &&
@@ -149,15 +163,20 @@
 
             env[env_index] = (char) 0;
 
-            if( use_home )
-                (void) strcpy( env, "HOME" );
-
-            env_value = getenv( env );
+            if( tilde_found )
+            {
+                if( strlen( env ) == 0 )
+                    expand_value = getenv( "HOME" );
+                else
+                    expand_value = get_user_home_directory( env );
+            }
+            else
+                expand_value = getenv( env );
 
-            if( env_value != (char *) NULL )
+            if( expand_value != (char *) NULL )
             {
-                (void) strcpy( &expanded_filename[dest], env_value );
-                dest += strlen( env_value );
+                (void) strcpy( &expanded_filename[dest], expand_value );
+                dest += strlen( expand_value );
                 i = new_i;
             }
             else
--- a/volume_io/Prog_utils/progress.c
+++ b/volume_io/Prog_utils/progress.c
@@ -92,13 +92,11 @@
     Real    current_time, constant, n_seconds_per;
     Real    time_so_far, est_total_time;
 
-    if( current_step < progress->next_check_step )
+    if( current_step < 1 || current_step < progress->next_check_step )
         return;
 
-    if( current_step < 1 || current_step > progress->n_steps )
-    {
-        HANDLE_INTERNAL_ERROR( "update_progress" );
-    }
+    if( current_step > progress->n_steps )
+        current_step = progress->n_steps;
 
     current_time = current_realtime_seconds();
 
--- a/volume_io/Testing/reorder_volume.c
+++ b/volume_io/Testing/reorder_volume.c
@@ -4,18 +4,24 @@
     int   argc,
     char  *argv[] )
 {
-    int                 i, a, n_dims, v, n_volumes;
+    int                 i, a, n_dims, v, n_volumes, sizes[MAX_DIMENSIONS];
+    int                 sizes_2d[MAX_DIMENSIONS];
     char                *input_filename, *output_filename, *string;
     char                *in_dim_names[MAX_DIMENSIONS];
-    Real                amount_done;
+    char                *out_dim_names[MAX_DIMENSIONS];
+    Real                amount_done, value;
     STRING              dim_names[MAX_DIMENSIONS];
     Volume              volume;
-    Minc_file           file;
+    General_transform   transform;
+    Minc_file           in_file, out_file;
     minc_output_options options, *options_ptr;
+    volume_input_struct volume_input;
+    nc_type             data_type;
+    BOOLEAN             signed_flag;
 
     if( argc < 3 )
     {
-        print( "Arguments?\n" );
+        print( "1: Arguments?\n" );
         return( 1 );
     }
 
@@ -43,15 +49,18 @@
 
     if( a >= argc )
     {
-        print( "Arguments?\n" );
+        print( "2: Arguments?\n" );
         return( 1 );
     }
 
     output_filename = argv[a];
     ++a;
 
-    if( a >= argc-N_DIMENSIONS )
-        options_ptr = NULL;
+    if( a > argc-N_DIMENSIONS )
+    {
+        print( "3: Arguments?\n" );
+        return( 1 );
+    }
     else
     {
         /*--- determine the output order */
@@ -71,36 +80,71 @@
                 (void) strcpy( dim_names[i], MIzspace );
             else
                 (void) strcpy( dim_names[i], string );
+
+            ALLOC( out_dim_names[i], strlen( dim_names[i] ) + 1 );
+            (void) strcpy( out_dim_names[i], dim_names[i] );
         }
     }
 
+    (void) start_volume_input( input_filename, N_DIMENSIONS,
+                               out_dim_names, NC_UNSPECIFIED, FALSE, 0.0, 0.0,
+                               TRUE, &volume, (minc_input_options *) NULL,
+                               &volume_input );
+
+    copy_general_transform( get_voxel_to_world_transform(volume),
+                            &transform );
+    get_volume_sizes( volume, sizes );
+
+    cancel_volume_input( volume, &volume_input );
+
     /*--- input the volume */
 
     volume = create_volume( n_dims, in_dim_names, NC_UNSPECIFIED, FALSE,
                             0.0, 0.0 );
 
-    file = initialize_minc_input( input_filename, volume,
-                                  (minc_input_options *) NULL );
+    in_file = initialize_minc_input( input_filename, volume,
+                                    (minc_input_options *) NULL );
 
-    n_volumes = get_n_input_volumes( file );
+    n_volumes = get_n_input_volumes( in_file );
     set_default_minc_output_options( &options );
     set_minc_output_dimensions_order( &options, get_volume_n_dimensions(volume),
                                       dim_names );
 
+    data_type = get_volume_nc_data_type( volume, &signed_flag );
+
+    out_file = initialize_minc_output( output_filename, 3, dim_names,
+                                       sizes, data_type, signed_flag,
+                                       get_volume_voxel_min(volume),
+                                       get_volume_voxel_max(volume),
+                                       get_volume_real_min(volume),
+                                       get_volume_real_max(volume),
+                                       &transform,
+                                       (minc_output_options *) NULL );
+
+    (void) copy_auxiliary_data_from_minc_file( out_file, input_filename,
+                                               "Axes reordered." );
+
     for_less( v, 0, n_volumes )
     {
-        while( input_more_minc_file( file, &amount_done ) )
+        while( input_more_minc_file( in_file, &amount_done ) )
         {}
 
-        (void) advance_input_volume( file );
+        (void) advance_input_volume( in_file );
+
+        if( output_minc_volume( out_file, volume ) != OK )
+            return( 1 );
 
-        if( output_modified_volume( output_filename, NC_UNSPECIFIED,
-                 FALSE, 0.0, 0.0, volume, input_filename,
-                 "Axes reordered.", options_ptr ) != OK )
-            return( 1 );
+/*
+        get_volume_sizes( volume, sizes_2d );
+        GET_VALUE_2D( value, volume, sizes_2d[0] / 2, sizes_2d[1] / 2 );
+        print( "Slice[%d]:  center value %g\n", v+1, value ); */
+
+        if( n_volumes > 0 && (v+1) % 10 == 0 )
+            print( "Done %d out of %d\n", v+1, n_volumes );
     }
 
-    (void) close_minc_input( file );
+    (void) close_minc_input( in_file );
+    (void) close_minc_output( out_file );
 
     return( 0 );
 }
--- a/volume_io/Volumes/input_mnc.c
+++ b/volume_io/Volumes/input_mnc.c
@@ -51,7 +51,6 @@
     BOOLEAN             converted_sign;
     nc_type             converted_type;
     STRING              signed_flag, last_dim_name;
-    char                *dim_names[MAX_VAR_DIMS];
     nc_type             file_datatype;
     int                 sizes[MAX_VAR_DIMS];
     double              file_separations[MAX_VAR_DIMS];
@@ -94,6 +93,7 @@
     if( file->cdfid == MI_ERROR )
     {
         print( "Error: opening MINC file \"%s\".\n", filename );
+        FREE( file );
         return( (Minc_file) 0 );
     }
 
@@ -119,6 +119,7 @@
         print( "Error: MINC file has only %d dims, volume requires %d.\n",
                file->n_file_dimensions, n_vol_dims );
         (void) miclose( file->cdfid );
+        FREE( file );
         return( (Minc_file) 0 );
     }
     else if( file->n_file_dimensions > MAX_VAR_DIMS )
@@ -126,14 +127,16 @@
         print( "Error: MINC file has %d dims, can only handle %d.\n",
                file->n_file_dimensions, MAX_VAR_DIMS );
         (void) miclose( file->cdfid );
+        FREE( file );
         return( (Minc_file) NULL );
     }
 
     for_less( d, 0, file->n_file_dimensions )
     {
-        ALLOC( dim_names[d], MAX_STRING_LENGTH + 1 );
+        ALLOC( file->dim_names[d], MAX_STRING_LENGTH + 1 );
 
-        (void) ncdiminq( file->cdfid, dim_vars[d], dim_names[d], &long_size );
+        (void) ncdiminq( file->cdfid, dim_vars[d], file->dim_names[d],
+                         &long_size );
         file->sizes_in_file[d] = long_size;
     }
 
@@ -141,7 +144,7 @@
 
     if( !match_dimension_names( get_volume_n_dimensions(volume),
                                 volume->dimension_names,
-                                file->n_file_dimensions, dim_names,
+                                file->n_file_dimensions, file->dim_names,
                                 file->axis_index_in_file ) )
     {
         print( "Error:  dimension names did not match: \n" );
@@ -154,9 +157,10 @@
         print( "\n" );
         print( "In File:\n" );
         for_less( d, 0, file->n_file_dimensions )
-            print( "%d: %s\n", d+1, dim_names[d] );
+            print( "%d: %s\n", d+1, file->dim_names[d] );
 
         (void) miclose( file->cdfid );
+        FREE( file );
         return( (Minc_file) NULL );
     }
 
@@ -183,7 +187,7 @@
 
     for_less( d, 0, file->n_file_dimensions )
     {
-        if( convert_dim_name_to_axis( dim_names[d], &axis ) )
+        if( convert_dim_name_to_axis( file->dim_names[d], &axis ) )
         {
             spatial_axis_indices[d] = axis;
             file->spatial_axes[axis] = d;
@@ -222,7 +226,7 @@
             dir_cosines[d][spatial_axis_indices[d]] = 1.0;
         }
 
-        dimvar = ncvarid( file->cdfid, dim_names[d] );
+        dimvar = ncvarid( file->cdfid, file->dim_names[d] );
         if( dimvar != MI_ERROR )
         {
             (void) miattget1( file->cdfid, dimvar, MIstep, NC_DOUBLE,
@@ -475,9 +479,6 @@
     if( different && volume->data != (char *) NULL )
         free_volume_data( volume );
 
-    for_less( d, 0, file->n_file_dimensions )
-        FREE( dim_names[d] );
-
     return( file );
 }
 
@@ -518,6 +519,8 @@
 public  Status  close_minc_input(
     Minc_file   file )
 {
+    int  d;
+
     if( file == (Minc_file) NULL )
     {
         print( "close_minc_input(): NULL file.\n" );
@@ -527,6 +530,9 @@
     (void) miclose( file->cdfid );
     (void) miicv_free( file->icv );
 
+    for_less( d, 0, file->n_file_dimensions )
+        FREE( file->dim_names[d] );
+
     delete_general_transform( &file->voxel_to_world_transform );
     FREE( file );
 
@@ -540,6 +546,7 @@
     int         src_ind[],
     int         to_dest_index[] )
 {
+    int     i, last_src_dim, inner_size, src_inner_step, dest_inner_step;
     int     d, n_src_dims, n_dest_dims, ind[MAX_DIMENSIONS];
     int     type_size, src_sizes[MAX_DIMENSIONS];
     int     dest_offset[MAX_DIMENSIONS], src_offset[MAX_DIMENSIONS];
@@ -583,13 +590,59 @@
         --n_dest_dims;
     }
 
+    if( n_src_dims > 0 )
+    {
+        last_src_dim = n_src_dims-1;
+        while( to_dest_index[last_src_dim] == INVALID_AXIS )
+            --last_src_dim;
+        inner_size = src_sizes[last_src_dim];
+        src_inner_step = src_offset[last_src_dim];
+        dest_inner_step = dest_offset[to_dest_index[last_src_dim]];
+    }
+    else
+    {
+        last_src_dim = 0;
+        inner_size = 1;
+        src_inner_step = 0;
+        dest_inner_step = 0;
+    }
+
     done = FALSE;
     while( !done )
     {
-        (void) memcpy( dest_ptr, src_ptr, type_size );
+        if( src_inner_step == 1 )
+        {
+            for_less( i, 0, inner_size )
+            {
+                (void) memcpy( dest_ptr, src_ptr, type_size );
+                ++src_ptr;
+                dest_ptr += dest_inner_step;
+            }
+        }
+        else if( dest_inner_step == 1 )
+        {
+            for_less( i, 0, inner_size )
+            {
+                (void) memcpy( dest_ptr, src_ptr, type_size );
+                src_ptr += src_inner_step;
+                ++dest_ptr;
+            }
+        }
+        else
+        {
+            for_less( i, 0, inner_size )
+            {
+                (void) memcpy( dest_ptr, src_ptr, type_size );
+                src_ptr += src_inner_step;
+                dest_ptr += dest_inner_step;
+            }
+        }
+
+        src_ptr -= src_inner_step * inner_size;
+        dest_ptr -= dest_inner_step * inner_size;
 
         done = TRUE;
-        d = n_src_dims-1;
+        d = last_src_dim-1;
         while( d >= 0 && done )
         {
             dest_index = to_dest_index[d];
--- a/volume_io/Volumes/input_volume.c
+++ b/volume_io/Volumes/input_volume.c
@@ -94,9 +94,12 @@
                                                        *volume, options );
         if( input_info->minc_file == (Minc_file) NULL )
             status = ERROR;
+        else
+        {
+            for_less( d, 0, MAX_DIMENSIONS )
+                input_info->axis_index_from_file[d] = d;
+        }
 
-        for_less( d, 0, MAX_DIMENSIONS )
-            input_info->axis_index_from_file[d] = d;
         break;
 #endif
 
--- a/volume_io/Volumes/output_mnc.c
+++ b/volume_io/Volumes/output_mnc.c
@@ -630,7 +630,7 @@
 
     for( d = file->n_file_dimensions-1;  d >= 0;  --d )
     {
-        if( to_volume[d] == INVALID_AXIS || n_slab >= file->n_slab_dims )
+        if( to_volume[d] != INVALID_AXIS && n_slab >= file->n_slab_dims )
             n_steps *= file->sizes_in_file[d];
         if( to_volume[d] != INVALID_AXIS )
             ++n_slab;
@@ -695,7 +695,7 @@
           correspond to volume dimensions */
 
     d = file->n_file_dimensions-1;
-    while( increment && d <= 0 )
+    while( increment && d >= 0 )
     {
         if( to_volume[d] == INVALID_AXIS )
         {
--- a/volume_io/Volumes/output_volume.c
+++ b/volume_io/Volumes/output_volume.c
@@ -61,9 +61,12 @@
     n_dims = get_volume_n_dimensions(volume);
     vol_dimension_names = get_volume_dimension_names( volume );
 
+    /*--- either get the output dim name ordering from the original
+          filename, the volume, or the options */
+
     if( options == NULL || strlen( options->dimension_names[0] ) == 0 )
     {
-        if( original_filename == NULL )
+        if( original_filename != NULL )
         {
             if( get_file_dimension_names( original_filename, n_dims,
                                           dim_names ) != OK )
--- a/volume_io/Volumes/volumes.c
+++ b/volume_io/Volumes/volumes.c
@@ -837,8 +837,7 @@
     convert_voxel_to_world( volume, voxel, x_world, y_world, z_world );
 }
 
-/* ----------------------------- MNI Header -----------------------------------
-@NAME       : convert_voxel_normal_vector_to_world
+/* ----------------------------- MNI Header -----------------------------------@NAME       : convert_voxel_normal_vector_to_world
 @INPUT      : volume
               x_voxel
               y_voxel
@@ -846,14 +845,13 @@
 @OUTPUT     : x_world
               y_world
               z_world
-@RETURNS    : 
+@RETURNS    :
 @DESCRIPTION: Converts a voxel vector to world coordinates.  Assumes the
               vector is a normal vector (ie. a derivative), so transforms by
               transpose of inverse transform.
 @CREATED    : Mar   1993           David MacDonald
-@MODIFIED   : 
+@MODIFIED   :
 ---------------------------------------------------------------------------- */
-
 public  void  convert_voxel_normal_vector_to_world(
     Volume          volume,
     Real            x_voxel,
@@ -887,6 +885,71 @@
 }
 
 /* ----------------------------- MNI Header -----------------------------------
+@NAME       : convert_voxel_vector_to_world
+@INPUT      : volume
+              voxel_vector
+@OUTPUT     : x_world
+              y_world
+              z_world
+@RETURNS    : 
+@DESCRIPTION: Converts a voxel vector to world coordinates.
+@CREATED    : Mar   1993           David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  convert_voxel_vector_to_world(
+    Volume          volume,
+    Real            voxel_vector[],
+    Real            *x_world,
+    Real            *y_world,
+    Real            *z_world )
+{
+    int         i;
+    Real        origin[MAX_DIMENSIONS], x0, y0, z0, x1, y1, z1;
+
+    for_less( i, 0, MAX_DIMENSIONS )
+        origin[i] = 0.0;
+
+    convert_voxel_to_world( volume, origin, &x0, &y0, &z0 );
+
+    convert_voxel_to_world( volume, voxel_vector, &x1, &y1, &z1 );
+
+    *x_world = x1 - x0;
+    *y_world = y1 - y0;
+    *z_world = z1 - z0;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : convert_world_vector_to_voxel
+@INPUT      : volume
+              x_world
+              y_world
+              z_world
+@OUTPUT     : voxel_vector
+@RETURNS    : 
+@DESCRIPTION: Converts a world vector to voxel coordinates.
+@CREATED    : Mar   1993           David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  convert_world_vector_to_voxel(
+    Volume          volume,
+    Real            x_world,
+    Real            y_world,
+    Real            z_world,
+    Real            voxel_vector[] )
+{
+    int         c;
+    Real        voxel[MAX_DIMENSIONS], origin[MAX_DIMENSIONS];
+
+    convert_world_to_voxel( volume, 0.0, 0.0, 0.0, origin );
+    convert_world_to_voxel( volume, x_world, y_world, z_world, voxel );
+
+    for_less( c, 0, get_volume_n_dimensions(volume) )
+        voxel_vector[c] = voxel[c] - origin[c];
+}
+
+/* ----------------------------- MNI Header -----------------------------------
 @NAME       : convert_world_to_voxel
 @INPUT      : volume
               x_world