changeset 656:301bccc66eb0

Initial revision
author neelin <neelin>
date Wed, 02 Nov 1994 16:21:09 +0000
parents 9e605a4a951e
children c65d018fc575
files progs/mincreshape/copy_data.c progs/mincreshape/mincreshape.c progs/mincreshape/mincreshape.h progs/mincreshape/mincreshape.man1
diffstat 4 files changed, 2811 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/progs/mincreshape/copy_data.c
@@ -0,0 +1,716 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : copy_data
+@DESCRIPTION: File containing routines to copy data when reshaping.
+@METHOD     : 
+@GLOBALS    : 
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   : $Log: copy_data.c,v $
+@MODIFIED   : Revision 1.1  1994-11-02 16:21:09  neelin
+@MODIFIED   : Initial revision
+@MODIFIED   :
+@COPYRIGHT  :
+              Copyright 1994 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+#ifndef lint
+static char rcsid[]="$Header: /private-cvsroot/minc/progs/mincreshape/copy_data.c,v 1.1 1994-11-02 16:21:09 neelin Exp $";
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <float.h>
+#include <limits.h>
+#include <string.h>
+#include <math.h>
+#include <minc.h>
+#include <minc_def.h>
+#include "mincreshape.h"
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : copy_data
+@INPUT      : reshape_info - information for reshaping volume
+@OUTPUT     : (none)
+@RETURNS    : (none)
+@DESCRIPTION: Copies data from one input volume to another, reorganizing
+              it according to the reshaping info.
+@METHOD     :
+@GLOBALS    :
+@CALLS      :
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   :
+---------------------------------------------------------------------------- */
+public void copy_data(Reshape_info *reshape_info)
+{
+   int idim, odim, out_ndims;
+   long block_begin[MAX_VAR_DIMS], block_end[MAX_VAR_DIMS];
+   long block_count[MAX_VAR_DIMS];
+   long block_cur_start[MAX_VAR_DIMS], block_cur_count[MAX_VAR_DIMS];
+   long chunk_begin[MAX_VAR_DIMS], chunk_end[MAX_VAR_DIMS];
+   long chunk_count[MAX_VAR_DIMS];
+   long chunk_cur_start[MAX_VAR_DIMS], chunk_cur_count[MAX_VAR_DIMS];
+   long total_size;
+   long num_min_values, num_max_values, num_values;
+   double fillvalue, *minmax_buffer;
+   void *chunk_data;
+
+   /* Get number of dimensions */
+   out_ndims = reshape_info->output_ndims;
+
+   /* Set up variables for looping through blocks */
+   for (odim=0; odim < out_ndims; odim++) {
+      idim = reshape_info->map_out_to_in[odim];
+      block_begin[odim] = 0;
+      block_end[odim] = ABS(reshape_info->input_count[idim]);
+      if (reshape_info->dim_used_in_block[odim])
+         block_count[odim] = ABS(reshape_info->input_count[idim]);
+      else
+         block_count[odim] = 1;
+   }
+
+   /* Figure out size of chunks and allocate space */
+   total_size = nctypelen(reshape_info->output_datatype);
+   for (odim=0; odim < out_ndims; odim++) {
+      total_size *= reshape_info->chunk_count[odim];
+   }
+   chunk_data = MALLOC(total_size);
+
+   /* Get enough space for image-min and max values for a block */
+   get_num_minmax_values(reshape_info, NULL, block_count, 
+                         &num_min_values, &num_max_values);
+   num_values = ((num_min_values > num_max_values) ?
+                 num_min_values : num_max_values);
+   if (num_values > 0)
+      minmax_buffer = MALLOC(num_values * sizeof(double));
+   else
+      minmax_buffer = NULL;
+
+   /* Print log message */
+   if (reshape_info->verbose) {
+      (void) fprintf(stderr, "Copying chunks:");
+      (void) fflush(stderr);
+   }
+
+   /* Loop through blocks */
+
+   nd_begin_looping(block_begin, block_cur_start, out_ndims);
+   while (!nd_end_of_loop(block_cur_start, block_end, out_ndims)) {
+
+      /* Set up count for current block */
+      nd_update_current_count(block_cur_start, block_count, block_end,
+                              block_cur_count, out_ndims);
+
+      /* Set up chunk begin, end and count */
+      for (odim=0; odim < out_ndims; odim++) {
+         chunk_begin[odim] = block_cur_start[odim];
+         chunk_end[odim] = chunk_begin[odim] + block_cur_count[odim];
+         chunk_count[odim] = reshape_info->chunk_count[odim];
+      }
+
+      /* Set up icv for normalization, set output image-max/min and 
+         calculate pixel fill value to use for current block */
+      handle_normalization(reshape_info, block_cur_start, block_cur_count,
+                           minmax_buffer, &fillvalue);
+
+      /* Loop through chunks */
+
+      nd_begin_looping(chunk_begin, chunk_cur_start, out_ndims);
+      while (!nd_end_of_loop(chunk_cur_start, chunk_end, out_ndims)) {
+
+         /* Set up count for current chunk */
+         nd_update_current_count(chunk_cur_start, chunk_count, chunk_end,
+                                 chunk_cur_count, out_ndims);
+
+         /* Print log message for chunk */
+         if (reshape_info->verbose) {
+            (void) fprintf(stderr, ".");
+            (void) fflush(stderr);
+         }
+
+         /* Copy the chunk */
+         copy_the_chunk(reshape_info, 
+                        chunk_cur_start, chunk_cur_count, chunk_data,
+                        fillvalue);
+
+         /* Increment chunk loop count */
+         nd_increment_loop(chunk_cur_start, chunk_begin, chunk_count,
+                           chunk_end, out_ndims);
+
+      }
+
+      /* Increment block loop count */
+      nd_increment_loop(block_cur_start, block_begin, block_count,
+                        block_end, out_ndims);
+
+   }
+
+   /* Free the chunk space */
+   FREE(chunk_data);
+
+   /* Print ending log message */
+   if (reshape_info->verbose) {
+      (void) fprintf(stderr, "Done.\n");
+      (void) fflush(stderr);
+   }
+
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_num_minmax_values
+@INPUT      : reshape_info - information for reshaping volume
+              block_start - start for a block (or NULL)
+              block_count - count for a block
+@OUTPUT     : num_min_values - number of image-min values to be read
+              num_max_values - number of image-max values to be read
+@RETURNS    : (nothing)
+@DESCRIPTION: Gets the number of image-min and image-max values that
+              correspond to a block. If block_start is NULL, then
+              it is assumed to translate to an input start of [0,0,...]. 
+              Note that only the true number of values for the specified 
+              block is computed (specifying a hyperslab that goes beyond 
+              file extents does not give a bigger number of values).
+@METHOD     :
+@GLOBALS    :
+@CALLS      :
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   :
+---------------------------------------------------------------------------- */
+public void get_num_minmax_values(Reshape_info *reshape_info,
+                                  long *block_start, long *block_count,
+                                  long *num_min_values, long *num_max_values)
+{
+   int iloop, idim, ndims;
+   int varid, inimgid;
+   long size;
+   long minmax_count[MAX_VAR_DIMS];
+   long input_block_start[MAX_VAR_DIMS];
+   long input_block_count[MAX_VAR_DIMS];
+   long *num_values;
+
+   /* Translate output block count to input count */
+   translate_output_to_input(reshape_info, block_start, block_count, 
+                             input_block_start, input_block_count);
+   if (block_start != NULL) {
+      truncate_input_vectors(reshape_info, input_block_start, 
+                             input_block_count);
+   }
+   inimgid = ncvarid(reshape_info->inmincid, MIimage);
+
+   /* Loop over image-min and image-max */
+
+   for (iloop=0; iloop < 2; iloop++) {
+
+      /* Get varid and pointer to return value */
+      ncopts = 0;
+      switch (iloop) {
+      case 0: 
+         varid = ncvarid(reshape_info->inmincid, MIimagemin); 
+         num_values = num_min_values;        /* Pointer to long */
+         break;
+      case 1: 
+         varid = ncvarid(reshape_info->inmincid, MIimagemax);
+         num_values = num_max_values;        /* Pointer to long */
+         break;
+      }
+      ncopts = NCOPTS_DEFAULT;
+
+      /* Translate block count to min or max count and work out the
+         total number of values. */
+      size = 0;
+      if (varid != MI_ERROR) {
+         (void) ncvarinq(reshape_info->inmincid, varid, NULL, NULL, 
+                         &ndims, NULL, NULL);
+         (void) mitranslate_coords(reshape_info->inmincid,
+                                   inimgid, input_block_count,
+                                   varid, minmax_count);
+         size = 1;
+         for (idim=0; idim < ndims; idim++) {
+            size *= minmax_count[idim];
+         }
+      }
+      *num_values = size;
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : handle_normalization
+@INPUT      : reshape_info - information for reshaping volume
+              block_start - start of current block
+              block_count - count for current block
+              minmax_buffer - buffer space for getting min and max
+                 values
+@OUTPUT     : fillvalue - pixel fill value to use for this block
+@RETURNS    : (none)
+@DESCRIPTION: Sets up icv for normalization to ensure that block is
+              internally normalized. Output image-max and min are set.
+              The appropriate pixel fill value is calculated for this
+              min and max (applies to the whole block).
+@METHOD     :
+@GLOBALS    :
+@CALLS      :
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   :
+---------------------------------------------------------------------------- */
+public void handle_normalization(Reshape_info *reshape_info,
+                                 long *block_start,
+                                 long *block_count,
+                                 double *minmax_buffer,
+                                 double *fillvalue)
+{
+   int iloop;
+   long num_min_values, num_max_values, ivalue;
+   int inmincid, inimgid, varid, icvid;
+   long minmax_start[MAX_VAR_DIMS], minmax_count[MAX_VAR_DIMS];
+   long input_block_start[MAX_VAR_DIMS], input_block_count[MAX_VAR_DIMS];
+   double minimum, maximum, *extreme, valid_min, valid_max, denom;
+   long num_values;
+   char *varname;
+   double sign;
+
+   /* Get input minc id, image id and icv id*/
+   inmincid = reshape_info->inmincid;
+   inimgid = ncvarid(inmincid, MIimage);
+   icvid = reshape_info->icvid;
+
+   /* Translate output block count to input count */
+   translate_output_to_input(reshape_info, block_start, block_count,
+                             input_block_start, input_block_count);
+   truncate_input_vectors(reshape_info, input_block_start, input_block_count);
+
+   /* Get number of min and max values */
+   get_num_minmax_values(reshape_info, block_start, block_count, 
+                         &num_min_values, &num_max_values);
+
+   /* Loop over image-min and image-max getting block min and max */
+
+   for (iloop=0; iloop < 2; iloop++) {
+
+      /* Get varid and pointer to min or max value */
+      switch (iloop) {
+      case 0: 
+         num_values = num_min_values;
+         varname = MIimagemin;
+         extreme = &minimum;
+         sign = -1.0;
+         break;
+      case 1: 
+         num_values = num_max_values;
+         varname = MIimagemax;
+         extreme = &maximum;
+         sign = +1.0;
+         break;
+      }
+
+      /* Get values from file */
+      if (num_values > 0) {
+         varid = ncvarid(inmincid, varname);
+         (void) mitranslate_coords(inmincid,
+                                   inimgid, input_block_start,
+                                   varid, minmax_start);
+         (void) mitranslate_coords(inmincid,
+                                   inimgid, input_block_count,
+                                   varid, minmax_count);
+         (void) mivarget(reshape_info->inmincid, varid, 
+                         minmax_start, minmax_count, 
+                         NC_DOUBLE, NULL, minmax_buffer);
+         *extreme = minmax_buffer[0];
+         for (ivalue=1; ivalue < num_values; ivalue++) {
+            if ((minmax_buffer[ivalue] * sign) > (*extreme * sign))
+               *extreme = minmax_buffer[ivalue];
+         }
+      }
+      else {
+         *extreme = 0.0;
+      }
+      if (reshape_info->need_fillvalue && 
+          (reshape_info->fillvalue == NOFILL) && 
+          (0.0 > (*extreme * sign)))
+         *extreme = 0.0;
+      
+   }
+
+   /* Modify the icv if necessary */
+   if (reshape_info->do_block_normalization) {
+      (void) miicv_detach(icvid);
+      (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MIN, minimum);
+      (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MAX, maximum);
+      (void) miicv_setint(icvid, MI_ICV_USER_NORM, TRUE);
+      (void) miicv_attach(icvid, inmincid, inimgid);
+   }
+
+   /* Save the image max and min for the block */
+   for (iloop=0; iloop < 2; iloop++) {
+
+      /* Get varid and pointer to min or max value */
+      switch (iloop) {
+      case 0: 
+         varname = MIimagemin;
+         extreme = &minimum;
+         break;
+      case 1: 
+         varname = MIimagemax;
+         extreme = &maximum;
+         break;
+      }
+
+      /* Save the value */
+      ncopts = 0;
+      varid = ncvarid(reshape_info->outmincid, varname);
+      ncopts = NCOPTS_DEFAULT;
+      if (varid != MI_ERROR) {
+         (void) mitranslate_coords(reshape_info->outmincid, 
+                                   reshape_info->outimgid, block_start,
+                                   varid, minmax_start);
+         (void) mivarput1(reshape_info->outmincid, varid, 
+                          minmax_start, NC_DOUBLE, NULL, extreme);
+      }
+   }
+
+   /* Calculate the pixel fill value */
+   *fillvalue = ((reshape_info->fillvalue == NOFILL) ? 0.0 :
+                 reshape_info->fillvalue);
+   if ((reshape_info->output_datatype != NC_FLOAT) &&
+       (reshape_info->output_datatype != NC_DOUBLE) &&
+       (*fillvalue != FILL)) {
+      (void) miicv_inqdbl(icvid, MI_ICV_VALID_MIN, &valid_min);
+      (void) miicv_inqdbl(icvid, MI_ICV_VALID_MAX, &valid_max);
+      denom = maximum - minimum;
+      if (denom == 0.0) {
+         *fillvalue = valid_min;
+      }
+      else {
+         *fillvalue = (*fillvalue - minimum) * 
+            (valid_max - valid_min) / denom + valid_min;
+      }
+   }
+
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : truncate_input_vectors
+@INPUT      : reshape_info - information for reshaping volume
+              input_start - start of input hyperslab (or NULL)
+              input_count - count for input hyperslab
+@OUTPUT     : input_start  - start of input hyperslab (or NULL)
+              input_count  - count for input hyperslab
+@RETURNS    : (nothing)
+@DESCRIPTION: Input_start and input_count are truncated to specify a legal hyperslab for 
+              the input file (if not specified, input_start is assumed to be
+              [0,0,...]).
+@METHOD     :
+@GLOBALS    :
+@CALLS      :
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   :
+---------------------------------------------------------------------------- */
+public void truncate_input_vectors(Reshape_info *reshape_info,
+                                   long *input_start,
+                                   long *input_count)
+{
+   int idim;
+   long first, last;
+
+   /* Check for NULL vectors */
+   if (input_count == NULL) return;
+
+   /* Loop through input dimensions */
+   for (idim=0; idim < reshape_info->input_ndims; idim++) {
+      first = ( (input_start != NULL) ? input_start[idim] : 0 );
+      last = first + input_count[idim];
+      if (first < 0)
+         input_start[idim] = 0;
+      else if (first >= reshape_info->input_size[idim])
+         input_start[idim] = reshape_info->input_size[idim] - 1;
+      if (last < 0)
+         input_count[idim] = 0;
+      else if (last >= reshape_info->input_size[idim])
+         input_count[idim] = reshape_info->input_size[idim] - 
+            input_start[idim];
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : translate_output_to_input
+@INPUT      : reshape_info - information for reshaping volume
+              output_start - start of output hyperslab (or NULL)
+              output_count - count for output hyperslab
+@OUTPUT     : input_start  - start of input hyperslab (or NULL)
+              input_count  - count for input hyperslab
+@RETURNS    : (nothing)
+@DESCRIPTION: Translates an output start and count to an input start and 
+              count. If output_start or input_start are NULL, then only the
+              count is translated.
+@METHOD     :
+@GLOBALS    :
+@CALLS      :
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   :
+---------------------------------------------------------------------------- */
+public void translate_output_to_input(Reshape_info *reshape_info,
+                                      long *output_start,
+                                      long *output_count,
+                                      long *input_start,
+                                      long *input_count)
+{
+   int idim, odim;
+
+   /* Check for NULL vectors */
+   if ((input_count == NULL) || (output_count == NULL)) return;
+
+   /* Loop through input dimensions */
+   for (idim=0; idim < reshape_info->input_ndims; idim++) {
+      odim = reshape_info->map_in_to_out[idim];
+      input_count[idim] = ((odim >= 0) ? output_count[odim] : 1);
+      if ((input_start != NULL) && (output_start != NULL)) {
+         input_start[idim] = reshape_info->input_start[idim];
+         if (odim >= 0) {
+            if (reshape_info->input_count[idim] > 0)
+               input_start[idim] += output_start[odim];
+            else
+               input_start[idim] -=
+                  (output_start[odim] + output_count[odim] - 1);
+         }
+      }
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : translate_input_to_output
+@INPUT      : reshape_info - information for reshaping volume
+              input_start  - start of output hyperslab (or NULL)
+              input_count  - count for output hyperslab
+@OUTPUT     : output_start - start of input hyperslab (or NULL)
+              output_count - count for input hyperslab
+@RETURNS    : (nothing)
+@DESCRIPTION: Translates an input start and count to an output start and 
+              count. If output_start or input_start are NULL, then only the
+              count is translated.
+@METHOD     :
+@GLOBALS    :
+@CALLS      :
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   :
+---------------------------------------------------------------------------- */
+public void translate_input_to_output(Reshape_info *reshape_info,
+                                      long *input_start,
+                                      long *input_count,
+                                      long *output_start,
+                                      long *output_count)
+{
+   int idim, odim;
+
+   /* Check for NULL vectors */
+   if ((input_count == NULL) || (output_count == NULL)) return;
+
+   /* Loop through output dimensions */
+   for (odim=0; odim < reshape_info->output_ndims; odim++) {
+      idim = reshape_info->map_out_to_in[odim];
+      output_count[odim] = input_count[idim];
+      if ((input_start != NULL) && (output_start != NULL)) {
+         if (reshape_info->input_count[idim] > 0)
+            output_start[odim] = input_start[idim] - 
+               reshape_info->input_start[idim];
+         else
+            output_start[odim] = reshape_info->input_start[idim] - 
+               (input_start[idim] + input_count[idim] - 1);
+      }
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : copy_the_chunk
+@INPUT      : reshape_info - information for reshaping volume
+              chunk_start - start of current block
+              chunk_count - count for current block
+              chunk_data - pointer to enough space for chunk
+              fillvalue - pixel value to zero volume, if necessary.
+@OUTPUT     : (none)
+@RETURNS    : (nothing)
+@DESCRIPTION: Copies the chunk from the input file to the output file.
+@METHOD     :
+@GLOBALS    :
+@CALLS      :
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   :
+---------------------------------------------------------------------------- */
+public void copy_the_chunk(Reshape_info *reshape_info,
+                           long chunk_start[],
+                           long chunk_count[],
+                           void *chunk_data,
+                           double fillvalue)
+{
+   int idim, odim, in_ndims, out_ndims;
+   long input_start[MAX_VAR_DIMS], input_count[MAX_VAR_DIMS];
+   long output_start[MAX_VAR_DIMS], output_count[MAX_VAR_DIMS];
+   long input_imap[MAX_VAR_DIMS], output_imap[MAX_VAR_DIMS];
+   void *output_origin;
+   int datatype_size;
+   long total_size, ipix, first, last;
+   int zero_data, really_copy_the_data;
+   union {
+      char c; short s; long l; float f; double d;
+   } value_buffer;
+
+   /* Get number of dimensions */
+   out_ndims = reshape_info->output_ndims;
+   in_ndims = reshape_info->input_ndims;
+
+   /* Get size of output datatype */
+   datatype_size = nctypelen(reshape_info->output_datatype);
+
+   /* Create input start and count */
+   translate_output_to_input(reshape_info, chunk_start, chunk_count,
+                             input_start, input_count);
+
+   /* Find out if we need to zero the volume and if we need to copy any
+      data */
+   zero_data = FALSE;
+   really_copy_the_data = TRUE;
+   total_size = 1;
+   for (idim=0; idim < in_ndims; idim++) {
+      first = input_start[idim];
+      last = input_start[idim] + input_count[idim] - 1;
+      if ((first < 0) || (last >= reshape_info->input_size[idim]))
+         zero_data = TRUE;
+      if ((last < 0) || (first >= reshape_info->input_size[idim]))
+         really_copy_the_data = FALSE;
+      total_size *= input_count[idim];
+   }
+
+   /* Make sure that input vectors are legal and translate them back 
+      to output */
+   truncate_input_vectors(reshape_info, input_start, input_count);
+   translate_input_to_output(reshape_info, input_start, input_count,
+                             output_start, output_count);
+
+   /* Write out zero data if needed */
+   if (zero_data) {
+      convert_value_from_double(fillvalue, 
+                                reshape_info->output_datatype,
+                                reshape_info->output_is_signed,
+                                &value_buffer);
+      for (ipix=0; ipix < total_size; ipix++) {
+         (void) memcpy((char *)chunk_data + ipix*datatype_size,
+                       &value_buffer, datatype_size);
+      }
+      (void) ncvarput(reshape_info->outmincid, reshape_info->outimgid,
+                      chunk_start, chunk_count, chunk_data);
+   }
+
+   /* Set up hypothetical imap variable for input */
+   for (idim=in_ndims-1; idim >= 0; idim--) {
+      input_imap[idim] = ((idim == in_ndims-1) ? 
+                          datatype_size :
+                          input_imap[idim+1] * input_count[idim+1]);
+   }
+
+   /* Create output imap variable from input one (re-ordering dimensions and
+      flipping). Also work out the chunk origin (point to byte for output
+      [0,0,0...]). */
+   output_origin = chunk_data;
+   for (odim=0; odim < out_ndims; odim++) {
+      idim = reshape_info->map_out_to_in[odim];
+      if (reshape_info->input_count[idim] > 0) {
+         output_imap[odim] = input_imap[idim];
+      }
+      else {
+         output_imap[odim] = -input_imap[idim];
+         output_origin = 
+            (void *) ((char *)output_origin - 
+                      (output_count[odim] - 1) * output_imap[odim]);
+      }
+   }
+
+   /* Should we really copy the data? */
+   if (really_copy_the_data) {
+
+      /* Read in the data */
+      (void) miicv_get(reshape_info->icvid, input_start, input_count, 
+                       chunk_data);
+   
+      /* Write it out */
+      (void) ncvarputg(reshape_info->outmincid, reshape_info->outimgid,
+                       output_start, output_count, NULL, output_imap, 
+                       output_origin);
+
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : convert_value_from_double
+@INPUT      : dvalue - double value to convert
+              datatype - type of desired value
+              is_signed - TRUE if desired value is signed
+@OUTPUT     : ptr - pointer to converted value
+@RETURNS    : (nothing)
+@DESCRIPTION: Converts a value from double to some other value.
+@METHOD     :
+@GLOBALS    :
+@CALLS      :
+@CREATED    : October 25, 1994 (Peter Neelin)
+@MODIFIED   :
+---------------------------------------------------------------------------- */
+public void convert_value_from_double(double dvalue, 
+                                      nc_type datatype, int is_signed,
+                                      void *ptr)
+{
+   switch (datatype) {
+   case NC_BYTE :
+      if (!is_signed) {
+         dvalue = MAX(0, dvalue);
+         dvalue = MIN(UCHAR_MAX, dvalue);
+         *((unsigned char *) ptr) = ROUND(dvalue);
+      }
+      else {
+         dvalue = MAX(SCHAR_MIN, dvalue);
+         dvalue = MIN(SCHAR_MAX, dvalue);
+         *((signed char *) ptr) = ROUND(dvalue);
+      }
+      break;
+   case NC_SHORT :
+      if (!is_signed) {
+         dvalue = MAX(0, dvalue);
+         dvalue = MIN(USHRT_MAX, dvalue);
+         *((unsigned short *) ptr) = ROUND(dvalue);
+      }
+      else {
+         dvalue = MAX(SHRT_MIN, dvalue);
+         dvalue = MIN(SHRT_MAX, dvalue);
+         *((signed short *) ptr) = ROUND(dvalue);
+      }
+      break;
+   case NC_LONG :
+      if (!is_signed) {
+         dvalue = MAX(0, dvalue);
+         dvalue = MIN(ULONG_MAX, dvalue);
+         *((unsigned long *) ptr) = ROUND(dvalue);
+      }
+      else {
+         dvalue = MAX(LONG_MIN, dvalue);
+         dvalue = MIN(LONG_MAX, dvalue);
+         *((signed long *) ptr) = ROUND(dvalue);
+      }
+      break;
+   case NC_FLOAT :
+      dvalue = MAX(-FLT_MAX,dvalue);
+      *((float *) ptr) = MIN(FLT_MAX,dvalue);
+      break;
+   case NC_DOUBLE :
+      *((double *) ptr) = dvalue;
+      break;
+   }
+}
new file mode 100644
--- /dev/null
+++ b/progs/mincreshape/mincreshape.c
@@ -0,0 +1,1598 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : mincreshape
+@INPUT      : argc, argv - command line arguments
+@OUTPUT     : (none)
+@RETURNS    : error status
+@DESCRIPTION: Program to allow reshaping of minc lattices: selecting a
+              a subrange (or superrange) of dimension indices, eliminating
+              dimensions, or re-ordering axes. As well, all icv conversions
+              are made accessible on the command line.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 10, 1994 (Peter Neelin)
+@MODIFIED   : $Log: mincreshape.c,v $
+@MODIFIED   : Revision 1.1  1994-11-02 16:21:24  neelin
+@MODIFIED   : Initial revision
+@MODIFIED   :
+@COPYRIGHT  :
+              Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+#ifndef lint
+static char rcsid[]="$Header: /private-cvsroot/minc/progs/mincreshape/mincreshape.c,v 1.1 1994-11-02 16:21:24 neelin Exp $";
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <float.h>
+#include <limits.h>
+#include <string.h>
+#include <math.h>
+#include <minc.h>
+#include <ParseArgv.h>
+#include <time_stamp.h>
+#include <minc_def.h>
+#include "mincreshape.h"
+
+/* Main program */
+
+public int main(int argc, char *argv[])
+{
+   Reshape_info reshape_info;
+
+   /* Get argument information and create the output file */
+   get_arginfo(argc, argv, &reshape_info);
+
+   /* Copy the data */
+   copy_data(&reshape_info);
+
+   /* Close the output file */
+   (void) miattputstr(reshape_info.outmincid, reshape_info.outimgid,
+                      MIcomplete, MI_TRUE);
+   (void) miclose(reshape_info.outmincid);
+
+   exit(EXIT_SUCCESS);
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_arginfo
+@INPUT      : argc - number of command-line arguments
+              argv - command-line arguments
+@OUTPUT     : reshape_info - information for reshaping file
+@RETURNS    : (nothing)
+@DESCRIPTION: Routine to get information from arguments about input and 
+              output files and reshaping.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 11, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public void get_arginfo(int argc, char *argv[],
+                        Reshape_info *reshape_info)
+{
+
+   /* Argument variables */
+   static int clobber = FALSE;
+   static int verbose = TRUE;
+   static nc_type datatype = NC_UNSPECIFIED;
+   static int is_signed = INT_MIN;
+   static double valid_range[2] = {DBL_MAX,DBL_MAX};
+   static double image_range[2] = {DBL_MAX,DBL_MAX};
+   static int do_norm = FALSE;
+   static double pixfillvalue = FILL;
+   static int do_scalar= FALSE;
+   static int direction = MI_ICV_ANYDIR;
+   static int xdirection = INT_MIN;
+   static int ydirection = INT_MIN;
+   static int zdirection = INT_MIN;
+   static int keep_aspect = FALSE;
+   static int image_size = MI_ICV_ANYSIZE;
+   static int row_size = MI_ICV_ANYSIZE;
+   static int col_size = MI_ICV_ANYSIZE;
+   static Dimsize_list dimsize_list = {0};
+   static char *axis_order[MAX_VAR_DIMS+1];
+   static Axis_ranges axis_ranges = {0};
+   static long hs_start[MAX_VAR_DIMS] = {LONG_MIN};
+   static long hs_count[MAX_VAR_DIMS] = {LONG_MIN};
+   static double fillvalue = NOFILL;
+   static int max_chunk_size_in_kb = DEFAULT_MAX_CHUNK_SIZE_IN_KB;
+
+   /* Argument table */
+   static ArgvInfo argTable[] = {
+      {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, 
+          "General options:"},
+      {"-clobber", ARGV_CONSTANT, (char *) TRUE, (char *) &clobber, 
+          "Overwrite existing file."},
+      {"-noclobber", ARGV_CONSTANT, (char *) FALSE, (char *) &clobber, 
+          "Do not overwrite existing file (default)."},
+      {"-verbose", ARGV_CONSTANT, (char *) TRUE, (char *) &verbose, 
+          "Print out log messages as processing is being done (default).\n"},
+      {"-quiet", ARGV_CONSTANT, (char *) FALSE, (char *) &verbose, 
+          "Do not print out any log messages."},
+      {"-max_chunk_size_in_kb", ARGV_INT, (char *) 0, 
+          (char *) &max_chunk_size_in_kb,
+          "Specify the maximum size of the copy buffer (in kbytes)."},
+
+      {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, 
+          "Image conversion options (pixel type and range):"},
+      {"-filetype", ARGV_CONSTANT, (char *) NC_UNSPECIFIED, (char *) &datatype,
+          "Don't do any type conversion (default)."},
+      {"-byte", ARGV_CONSTANT, (char *) NC_BYTE, (char *) &datatype,
+          "Convert to  byte data"},
+      {"-short", ARGV_CONSTANT, (char *) NC_SHORT, (char *) &datatype,
+          "Convert to short integer data"},
+      {"-long", ARGV_CONSTANT, (char *) NC_LONG, (char *) &datatype,
+          "Convert to long integer data"},
+      {"-float", ARGV_CONSTANT, (char *) NC_FLOAT, (char *) &datatype,
+          "Convert to single-precision floating-point data"},
+      {"-double", ARGV_CONSTANT, (char *) NC_DOUBLE, (char *) &datatype,
+          "Convert to double-precision floating-point data"},
+      {"-signed", ARGV_CONSTANT, (char *) TRUE, (char *) &is_signed,
+          "Convert to signed integer data"},
+      {"-unsigned", ARGV_CONSTANT, (char *) FALSE, (char *) &is_signed,
+          "Convert to unsigned integer data"},
+      {"-valid_range", ARGV_FLOAT, (char *) 2, (char *) valid_range,
+          "Valid range for output data (pixel values)"},
+
+      {"-image_range", ARGV_FLOAT, (char *) 2, (char *) image_range,
+          "Normalize images to a given minimum and maximum"},
+      {"-normalize", ARGV_CONSTANT, (char *) TRUE, (char *) &do_norm,
+          "Normalize images to file minimum and maximum."},
+      {"-nonormalize", ARGV_CONSTANT, (char *) FALSE, (char *) &do_norm,
+          "Do not normalize images (default)."},
+      {"-nopixfill", ARGV_FUNC, (char *) get_fillvalue, 
+          (char *) &pixfillvalue,
+          "Do not convert out-of-range values in input file."},
+      {"-pixfill", ARGV_FUNC, (char *) get_fillvalue, 
+          (char *) &pixfillvalue,
+          "Replace out-of-range values in input file by smallest value (default)."},
+      {"-pixfillvalue", ARGV_FLOAT, (char *) 0, 
+          (char *) &pixfillvalue,
+          "Specify new value to replace out-of-range values in input file."},
+
+      {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, 
+          "Image conversion options (dimension direction and size):"},
+      {"-scalar", ARGV_CONSTANT, (char *) TRUE, (char *) &do_scalar,
+          "Convert vector images to scalar images."},
+      {"-noscalar", ARGV_CONSTANT, (char *) FALSE, (char *) &do_scalar,
+          "Do not convert vector images to scalar images (default)."},
+
+      {"+direction", ARGV_CONSTANT, (char *) MI_ICV_POSITIVE, 
+          (char *) &direction,
+          "Flip images to give positive step value for spatial axes."},
+      {"-direction", ARGV_CONSTANT, (char *) MI_ICV_NEGATIVE, 
+          (char *) &direction,
+          "Flip images to give negative step value for spatial axes."},
+      {"-anydirection", ARGV_CONSTANT, (char *) MI_ICV_ANYDIR, 
+          (char *) &direction,
+          "Don't flip images along spatial axes (default)."},
+      {"+xdirection", ARGV_CONSTANT, (char *) MI_ICV_POSITIVE, 
+          (char *) &xdirection,
+          "Flip images to give positive xspace:step value (left-to-right)."},
+      {"-xdirection", ARGV_CONSTANT, (char *) MI_ICV_NEGATIVE, 
+          (char *) &xdirection,
+          "Flip images to give negative xspace:step value (right-to-left)."},
+      {"-xanydirection", ARGV_CONSTANT, (char *) MI_ICV_ANYDIR, 
+          (char *) &xdirection,
+          "Don't flip images along x-axis."},
+      {"+ydirection", ARGV_CONSTANT, (char *) MI_ICV_POSITIVE, 
+          (char *) &ydirection,
+          "Flip images to give positive yspace:step value (post-to-ant)."},
+      {"-ydirection", ARGV_CONSTANT, (char *) MI_ICV_NEGATIVE, 
+          (char *) &ydirection,
+          "Flip images to give negative yspace:step value (ant-to-post)."},
+      {"-yanydirection", ARGV_CONSTANT, (char *) MI_ICV_ANYDIR, 
+          (char *) &ydirection,
+          "Don't flip images along y-axis."},
+      {"+zdirection", ARGV_CONSTANT, (char *) MI_ICV_POSITIVE, 
+          (char *) &zdirection,
+          "Flip images to give positive zspace:step value (inf-to-sup)."},
+      {"-zdirection", ARGV_CONSTANT, (char *) MI_ICV_NEGATIVE, 
+          (char *) &zdirection,
+          "Flip images to give negative zspace:step value (sup-to-inf)."},
+      {"-zanydirection", ARGV_CONSTANT, (char *) MI_ICV_ANYDIR, 
+          (char *) &zdirection,
+          "Don't flip images along z-axis."},
+
+      {"-keepaspect", ARGV_CONSTANT, (char *) TRUE, (char *) &keep_aspect,
+          "Preserve aspect ratio when resizing images."},
+      {"-nokeepaspect", ARGV_CONSTANT, (char *) FALSE, (char *) &keep_aspect,
+          "Do not preserve aspect ratio when resizing images (default)."},
+
+      {"-imgsize", ARGV_INT, (char *) 0, (char *) &image_size,
+          "Specify the desired image size."},
+      {"-rowsize", ARGV_INT, (char *) 0, (char *) &row_size,
+          "Specify the desired number of rows in the image."},
+      {"-colsize", ARGV_INT, (char *) 0, (char *) &col_size,
+          "Specify the desired number of columns in the image."},
+      {"-dimsize", ARGV_FUNC, (char *) get_dimsize, 
+          (char *) &dimsize_list,
+          "Specify the size of a named dimension (<dimension>=<size>)."},
+
+      {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, 
+          "Reshaping options:"},
+      {"-transverse", ARGV_FUNC, (char *) get_axis_order, 
+          (char *) axis_order,
+          "Write out transverse slices"},
+      {"-sagittal", ARGV_FUNC, (char *) get_axis_order, 
+          (char *) axis_order,
+          "Write out sagittal slices"},
+      {"-coronal", ARGV_FUNC, (char *) get_axis_order, 
+          (char *) axis_order,
+          "Write out coronal slices"},
+      {"-dimorder", ARGV_FUNC, (char *) get_axis_order, 
+          (char *) axis_order,
+          "Specify dimension order (<dim1>,<dim2>,<dim3>,...)."},
+      {"-dimrange", ARGV_FUNC, (char *) get_axis_range, 
+          (char *) &axis_ranges,
+          "Specify range of dimension subscripts (<dim>=<start>[,<count>])."},
+      {"-start", ARGV_FUNC, (char *) get_arg_vector, (char *) hs_start,
+          "Specifies corner of hyperslab (C conventions for indices)"},
+      {"-count", ARGV_FUNC, (char *) get_arg_vector, (char *) hs_count,
+          "Specifies edge lengths of hyperslab to read"},
+
+      {NULL, ARGV_HELP, (char *) NULL, (char *) NULL, 
+          "Missing data options:"},
+      {"-nofill", ARGV_FUNC, (char *) get_fillvalue, 
+          (char *) &fillvalue,
+          "Use value zero for points outside of input volume (default)"},
+      {"-fill", ARGV_FUNC, (char *) get_fillvalue, 
+          (char *) &fillvalue,
+          "Use a fill value for points outside of input volume"},
+      {"-fillvalue", ARGV_FLOAT, (char *) 0, 
+          (char *) &fillvalue,
+          "Specify a fill value for points outside of input volume"},
+
+      {NULL, ARGV_END, NULL, NULL, NULL}
+   };
+
+   /* Other variables */
+   char *infile, *outfile;
+   char *history, *pname;
+   int icvid;
+
+   /* Get the history information and program name */
+   history = time_stamp(argc, argv);
+   pname = argv[0];
+
+   /* Call ParseArgv */
+   if (ParseArgv(&argc, argv, argTable, 0) || (argc!=3)) {
+      (void) fprintf(stderr, 
+                     "\nUsage: %s [<options>] <infile> <outfile>\n", pname);
+      (void) fprintf(stderr,   
+                     "       %s [-help]\n\n", pname);
+      exit(EXIT_FAILURE);
+   }
+   infile = argv[1];
+   outfile = argv[2];
+
+   /* Save verbose setting */
+   reshape_info->verbose = verbose;
+
+   /* Check the x, y and z directions */
+   if (xdirection == INT_MIN) xdirection = direction;
+   if (ydirection == INT_MIN) ydirection = direction;
+   if (zdirection == INT_MIN) zdirection = direction;
+
+   /* Check the row and column size */
+   if (row_size == MI_ICV_ANYSIZE) row_size = image_size;
+   if (col_size == MI_ICV_ANYSIZE) col_size = image_size;
+
+   /* Check for normalization to specified range */
+   if (image_range[0] != DBL_MAX) do_norm = TRUE;
+
+   /* Open the input file */
+   reshape_info->inmincid = miopen(infile, NC_NOWRITE);
+
+   /* Get the default datatype */
+   get_default_datatype(reshape_info->inmincid, &datatype, &is_signed,
+                        valid_range);
+   reshape_info->output_datatype = datatype;
+   reshape_info->output_is_signed = is_signed;
+
+   /* Create the icv */
+   reshape_info->icvid = miicv_create();
+   icvid = reshape_info->icvid;
+
+   /* Set the icv properties */
+
+   /* Set datatype properties (get min and max for type from icv) */
+   (void) miicv_setint(icvid, MI_ICV_TYPE, datatype);
+   if (is_signed != INT_MIN) {
+      if (is_signed)
+         (void) miicv_setstr(icvid, MI_ICV_SIGN, MI_SIGNED);
+      else
+         (void) miicv_setstr(icvid, MI_ICV_SIGN, MI_UNSIGNED);
+   }
+   if (valid_range[0] != DBL_MAX) {
+      (void) miicv_setdbl(icvid, MI_ICV_VALID_MIN, valid_range[0]);
+      (void) miicv_setdbl(icvid, MI_ICV_VALID_MAX, valid_range[1]);
+   }
+
+   /* Check for normalization */
+   (void) miicv_setint(icvid, MI_ICV_DO_NORM, do_norm);
+   (void) miicv_setint(icvid, MI_ICV_USER_NORM, (image_range[0] != DBL_MAX));
+   (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MIN, image_range[0]);
+   (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MAX, image_range[1]);
+
+   /* Check for pixel fill value conversion */
+   (void) miicv_setint(icvid, MI_ICV_DO_FILLVALUE,
+                       (pixfillvalue != NOFILL));
+   (void) miicv_setdbl(icvid, MI_ICV_FILLVALUE, pixfillvalue);
+
+   /* Set up for dimension conversion */
+   (void) miicv_setint(icvid, MI_ICV_DO_DIM_CONV, TRUE);
+   (void) miicv_setint(icvid, MI_ICV_DO_SCALAR, do_scalar);
+   (void) miicv_setint(icvid, MI_ICV_XDIM_DIR, xdirection);
+   (void) miicv_setint(icvid, MI_ICV_YDIM_DIR, ydirection);
+   (void) miicv_setint(icvid, MI_ICV_ZDIM_DIR, zdirection);
+
+   /* Set up for image resizing */
+   (void) miicv_setint(icvid, MI_ICV_KEEP_ASPECT, keep_aspect);
+   (void) miicv_setint(icvid, MI_ICV_ADIM_SIZE, col_size);
+   (void) miicv_setint(icvid, MI_ICV_BDIM_SIZE, row_size);
+   setup_dim_sizes(icvid, reshape_info->inmincid, &dimsize_list);
+
+   /* Save reshaping information */
+   setup_reshaping_info(icvid, reshape_info->inmincid, 
+                        do_norm, fillvalue, do_scalar, 
+                        axis_order, &axis_ranges, hs_start, hs_count,
+                        max_chunk_size_in_kb,
+                        reshape_info);
+
+   /* Attach the icv */
+   (void) miicv_attach(icvid, reshape_info->inmincid, 
+                       ncvarid(reshape_info->inmincid, MIimage));
+
+   /* Create the output file */
+   reshape_info->outmincid = 
+      micreate(outfile, (clobber ? NC_CLOBBER : NC_NOCLOBBER));
+   setup_output_file(reshape_info->outmincid, history, reshape_info);
+
+   return;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_fillvalue
+@INPUT      : dst - Pointer to client data from argument table
+              key - argument key
+              nextArg - argument following key
+@OUTPUT     : (nothing) 
+@RETURNS    : FALSE so that ParseArgv will not discard nextArg
+@DESCRIPTION: Routine called by ParseArgv to set the fill value
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public int get_fillvalue(char *dst, char *key, char *nextArg)
+{     /* ARGSUSED */
+   double *dptr;
+
+   /* Get pointer to client data */
+   dptr = (double *) dst;
+
+   /* Check key for fill value to set */
+   if ((strcmp(key, "-fill") == 0) ||
+       (strcmp(key, "-pixfill") == 0)) {
+      *dptr = FILL;
+   }
+   else if ((strcmp(key, "-nofill") == 0) || 
+            (strcmp(key, "-nopixfill") == 0)) {
+      *dptr = NOFILL;
+   }
+
+   return FALSE;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_dimsize
+@INPUT      : dst - Pointer to client data from argument table
+              key - argument key
+              nextArg - argument following key
+@OUTPUT     : (nothing) 
+@RETURNS    : TRUE so that ParseArgv will discard nextArg
+@DESCRIPTION: Routine called by ParseArgv to get a dimension size
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public int get_dimsize(char *dst, char *key, char *nextArg)
+{     /* ARGSUSED */
+   Dimsize_list *dimsize_list;
+   char *size_string;
+   int ientry;
+   char *cur;
+
+   /* Get pointer to client data */
+   dimsize_list = (Dimsize_list *) dst;
+
+   /* Check for next argument */
+   if (nextArg == NULL) {
+      (void) fprintf(stderr, 
+                     "\"%s\" option requires an additional argument\n",
+                     key);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Check that we have enough space in the list */
+   if (dimsize_list->nentries >= MAX_VAR_DIMS) {
+      (void) fprintf(stderr, "Too many \"%s\" options.\n", key);
+      exit(EXIT_FAILURE);
+   }
+   ientry = dimsize_list->nentries;
+
+   /* Parse the argument (<dim name>=<size>) */
+
+   /* Remove leading space */
+   while (ISSPACE(*nextArg)) nextArg++;
+   dimsize_list->name[ientry] = nextArg;
+
+   /* Find the '=' */
+   size_string = strchr(nextArg, '=');
+   if ((size_string == NULL) || (size_string == nextArg)) {
+      (void) fprintf(stderr,
+                     "\"%s\" option requires the argument <dim>=<size>\n",
+                     key);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Remove trailing blanks on name */
+   cur = size_string - 1;
+   while ((cur>=nextArg) && ISSPACE(*cur)) cur--;
+   cur++;
+   *cur = '\0';
+
+   /* Get the size */
+   size_string++;
+   dimsize_list->size[ientry] = strtol(size_string, &cur, 0);
+   if (cur == size_string) {
+      (void) fprintf(stderr,
+                     "\"%s\" option requires the argument <dim>=<size>\n",
+                     key);
+      exit(EXIT_FAILURE);
+   }
+
+   dimsize_list->nentries++;
+
+   return TRUE;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_axis_order
+@INPUT      : dst - Pointer to client data from argument table
+              key - argument key
+              nextArg - argument following key
+@OUTPUT     : (nothing) 
+@RETURNS    : TRUE or FALSE (so that ParseArgv will discard nextArg only
+              when needed)
+@DESCRIPTION: Routine called by ParseArgv to set the axis order
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public int get_axis_order(char *dst, char *key, char *nextArg)
+{     /* ARGSUSED */
+   char **axis_order;
+   char *cur;
+   int ndims;
+
+   /* Get pointer to client data */
+   axis_order = (char **) dst;
+
+   /* Check key */
+   if (strcmp(key, "-transverse") == 0) {
+      axis_order[0] = MIzspace;
+      axis_order[1] = MIyspace;
+      axis_order[2] = MIxspace;
+      return FALSE;
+   }
+   if (strcmp(key, "-sagittal") == 0) {
+      axis_order[0] = MIxspace;
+      axis_order[1] = MIzspace;
+      axis_order[2] = MIyspace;
+      return FALSE;
+   }
+   if (strcmp(key, "-coronal") == 0) {
+      axis_order[0] = MIyspace;
+      axis_order[1] = MIzspace;
+      axis_order[2] = MIxspace;
+      return FALSE;
+   }
+
+   /* Make sure that we have a "-dimorder" argument */
+   if (strcmp(key, "-dimorder") != 0) {
+      (void) fprintf(stderr, 
+                     "Unrecognized option \"%s\": internal program error.\n",
+                     key);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Check for next argument */
+   if (nextArg == NULL) {
+      (void) fprintf(stderr, 
+                     "\"%s\" option requires an additional argument\n",
+                     key);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Set up pointers to end of string and first non-space character */
+   cur = nextArg;
+   while (ISSPACE(*cur)) cur++;
+   ndims = 0;
+
+   /* Loop through string looking for space or comma-separated names */
+   while ((ndims < MAX_VAR_DIMS) && (*cur!='\0')) {
+
+      /* Get string */
+      axis_order[ndims] = cur;
+
+      /* Search for end of dimension name */
+      while (!ISSPACE(*cur) && (*cur != ',') && (*cur != '\0')) cur++;
+      if (*cur != '\0') {
+         *cur = '\0';
+         cur++;
+      }
+      ndims++;
+
+      /* Skip any spaces */
+      while (ISSPACE(*cur)) cur++;
+
+   }
+
+   /* Terminate list with NULL */
+   axis_order[ndims] = NULL;
+
+   return TRUE;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_axis_range
+@INPUT      : dst - Pointer to client data from argument table
+              key - argument key
+              nextArg - argument following key
+@OUTPUT     : (nothing) 
+@RETURNS    : TRUE so that ParseArgv will discard nextArg
+@DESCRIPTION: Routine called by ParseArgv to set the axis range
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public int get_axis_range(char *dst, char *key, char *nextArg)
+{     /* ARGSUSED */
+   Axis_ranges *axis_ranges;
+   int ientry;
+   char *num_string, *cur;
+
+   /* Get pointer to client data */
+   axis_ranges = (Axis_ranges *) dst;
+
+   /* Check for next argument */
+   if (nextArg == NULL) {
+      (void) fprintf(stderr, 
+                     "\"%s\" option requires an additional argument\n",
+                     key);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Check that we have enough space in the list */
+   if (axis_ranges->nentries >= MAX_VAR_DIMS) {
+      (void) fprintf(stderr, "Too many \"%s\" options.\n", key);
+      exit(EXIT_FAILURE);
+   }
+   ientry = axis_ranges->nentries;
+
+   /* Parse the argument (<dim name>=<start>,[<count>]) */
+
+   /* Remove leading space */
+   while (ISSPACE(*nextArg)) nextArg++;
+   axis_ranges->name[ientry] = nextArg;
+
+   /* Find the '=' */
+   num_string = strchr(nextArg, '=');
+   if ((num_string == NULL) || (num_string == nextArg)) {
+      (void) fprintf(stderr,
+         "\"%s\" option requires the argument <dim>=<start>[,<count>]\n",
+                     key);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Remove trailing blanks on name */
+   cur = num_string - 1;
+   while ((cur>=nextArg) && ISSPACE(*cur)) cur--;
+   cur++;
+   *cur = '\0';
+
+   /* Get the start */
+   num_string++;
+   axis_ranges->start[ientry] = strtol(num_string, &cur, 0);
+   if (cur == num_string) {
+      (void) fprintf(stderr,
+         "\"%s\" option requires the argument <dim>=<start>[,<count>]\n",
+                     key);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Skip any spaces */
+   while (ISSPACE(*cur)) cur++;
+   
+   /* Skip an optional comma */
+   if (*cur == ',') cur++;
+
+   /* Look for a count string */
+   num_string = cur;
+   axis_ranges->count[ientry] = strtol(num_string, &cur, 0);
+   if ((cur == num_string) || (axis_ranges->count[ientry] == 0)) {
+      axis_ranges->count[ientry] = 0;
+   }
+
+   axis_ranges->nentries++;
+
+   return TRUE;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_arg_vector
+@INPUT      : key - argv key string (-start, -count)
+              nextArg - string from which vector should be read
+@OUTPUT     : dst - pointer to vector of longs into which values should
+                 be written (padded with LONG_MIN)
+@RETURNS    : TRUE, since nextArg is used (unless it is NULL)
+@DESCRIPTION: Parses a command-line argument into a vector of longs. The
+              string should contain at most MAX_VAR_DIMS comma separated 
+              integer values (spaces are skipped).
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : June 10, 1993 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public int get_arg_vector(char *dst, char *key, char *nextArg)
+{     /* ARGSUSED */
+
+   long *vector;
+   int nvals, i;
+   char *cur, *end, *prev;
+
+   /* Check for following argument */
+   if (nextArg == NULL) {
+      (void) fprintf(stderr, 
+                     "\"%s\" option requires an additional argument\n",
+                     key);
+      return FALSE;
+   }
+
+   /* Get pointer to vector of longs */
+   vector = (long *) dst;
+
+   /* Set up pointers to end of string and first non-space character */
+   end = nextArg + strlen(nextArg);
+   cur = nextArg;
+   while (ISSPACE(*cur)) cur++;
+   nvals = 0;
+
+   /* Loop through string looking for integers */
+   while ((nvals < MAX_VAR_DIMS) && (cur!=end)) {
+
+      /* Get integer */
+      prev = cur;
+      vector[nvals] = strtol(prev, &cur, 0);
+      if (cur == prev) {
+         (void) fprintf(stderr, 
+            "expected vector of integers for \"%s\", but got \"%s\"\n", 
+                        key, nextArg);
+         exit(EXIT_FAILURE);
+      }
+      nvals++;
+
+      /* Skip any spaces */
+      while (ISSPACE(*cur)) cur++;
+
+      /* Skip an optional comma */
+      if (*cur == VECTOR_SEPARATOR) cur++;
+
+   }
+
+   /* Pad with LONG_MIN */
+   for (i=nvals; i < MAX_VAR_DIMS; i++) {
+      vector[i] = LONG_MIN;
+   }
+
+   return TRUE;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_default_datatype
+@INPUT      : mincid - id of input minc file
+@OUTPUT     : datatype - datatype of file
+              is_signed - TRUE if data is signed, FALSE if not. Defaults
+                 to FALSE for byte, TRUE otherwise.
+              valid_range - DBL_MAX if not known
+@RETURNS    : (nothing)
+@DESCRIPTION: Routine to get the datatype info from a file. If datatype
+              is not NC_UNSPECIFIED, then is_signed only is set to its 
+              default. Otherwise, is_signed is only modified if it is set 
+              to INT_MIN and valid_range is only modified if it is set to 
+              DBL_MAX.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public void get_default_datatype(int mincid, nc_type *datatype, int *is_signed,
+                                 double valid_range[2])
+{
+   int imgid;
+   int status;
+   double vrange[2];
+   char string[MI_MAX_ATTSTR_LEN];
+   int length;
+
+   /* Get the image variable id */
+   imgid = ncvarid(mincid, MIimage);
+
+   /* Check that datatype is not specified */
+   if (*datatype != NC_UNSPECIFIED) {
+      if (*is_signed == INT_MIN) {
+         *is_signed = ((*datatype == NC_BYTE) ? FALSE : TRUE);
+      }
+      return;
+   }
+
+   /* Get data type */
+   (void) ncvarinq(mincid, imgid, NULL, datatype, NULL, NULL, NULL);
+
+   /* Look for sign if needed */
+   if (*is_signed == INT_MIN) {
+      ncopts = 0;
+      if (miattgetstr(mincid, imgid, MIsigntype, sizeof(string), string) 
+          != NULL) {
+         if (strcmp(string, MI_SIGNED) == 0)
+            *is_signed = TRUE;
+         else if (strcmp(string, MI_UNSIGNED) == 0)
+            *is_signed = FALSE;
+      }
+      ncopts = NCOPTS_DEFAULT;
+      if (*is_signed == INT_MIN) {
+         *is_signed = ((*datatype == NC_BYTE) ? FALSE : TRUE);
+      }
+   }
+
+   /* Look for valid range if needed */
+   if (valid_range[0] == DBL_MAX) {
+      ncopts = 0;
+      status=miattget(mincid, imgid, MIvalid_range, 
+                      NC_DOUBLE, 2, vrange, &length);
+      if ((status!=MI_ERROR) && (length==2)) {
+         if (vrange[1] > vrange[0]) {
+            valid_range[0] = vrange[0];
+            valid_range[1] = vrange[1];
+         }
+         else {
+            valid_range[0] = vrange[1];
+            valid_range[1] = vrange[0];
+         }
+      }
+      else {
+         status=miattget1(mincid, imgid, MIvalid_max, 
+                          NC_DOUBLE, &vrange[1]);
+         if (status!=MI_ERROR) valid_range[1] = vrange[1];
+  
+         status=miattget1(mincid, imgid, MIvalid_min, 
+                          NC_DOUBLE, &vrange[0]);
+         if (status!=MI_ERROR)
+         if (status!=MI_ERROR) valid_range[1] = vrange[1];
+
+      }
+      ncopts = NCOPTS_DEFAULT;
+   }
+
+   return;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : setup_dim_sizes
+@INPUT      : mincid - id of input minc file
+              dimsize_list - list of dimension names and sizes
+@OUTPUT     : icvid - icvid to modify
+@RETURNS    : (nothing)
+@DESCRIPTION: Routine to modify an icv so that the appropriate dimensions
+              have given sizes
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : May 18, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public void setup_dim_sizes(int icvid, int mincid, Dimsize_list *dimsize_list)
+{
+   int ientry, idim;
+   int imgid, dimid;
+   int ndims;
+   int dim[MAX_VAR_DIMS];
+   char dimname[MAX_NC_NAME];
+   int image_dim, n_image_dims;
+
+   /* Get image dimension info */
+   imgid = ncvarid(mincid, MIimage);
+   (void) ncvarinq(mincid, imgid, NULL, NULL, &ndims, dim, NULL);
+   if (ndims > 0) {
+      (void) ncdiminq(mincid, dim[ndims-1], dimname, NULL);
+      if (strcmp(dimname, MIvector_dimension) == 0) ndims--;
+   }
+
+   /* Get default number of image dimensions */
+   (void) miicv_inqint(icvid, MI_ICV_NUM_IMGDIMS, &n_image_dims);
+
+   /* Loop through list of names, looking for dimensions */
+   for (ientry=0; ientry < dimsize_list->nentries; ientry++) {
+      ncopts = 0;
+      dimid = ncdimid(mincid, dimsize_list->name[ientry]);
+      ncopts = NCOPTS_DEFAULT;
+      for (idim=0; idim < ndims; idim++) {
+         if (dim[idim] == dimid) break;
+      }
+      if (idim < ndims) {
+         image_dim = ndims - idim - 1;
+         (void) miicv_setint(icvid, MI_ICV_DIM_SIZE+image_dim,
+                             dimsize_list->size[ientry]);
+         if (n_image_dims < image_dim+1)
+            n_image_dims = image_dim+1;
+      }
+      else {
+         (void) fprintf(stderr, "Unable to set size of dimension \"%s\"\n",
+                        dimsize_list->name[ientry]);
+         exit(EXIT_FAILURE);
+      }
+   }
+
+   /* Update number of image dimensions, if needed */
+   if (n_image_dims > 2) {
+      (void) miicv_setint(icvid, MI_ICV_NUM_IMGDIMS, n_image_dims);
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : setup_reshaping_info
+@INPUT      : mincid - id of input minc file
+              do_norm - indicates if normalization is being done already
+                 through the icv
+              fillvalue - value to use where there is no input value
+              do_scalar - TRUE if vector image should be converted to scalar
+              axis_order - order of dimensions by name
+              axis_ranges - range of subscripts for each axis
+              hs_start - starting coordinate of hyperslab to read
+              hs_count - edge lengths of hyperslab to read
+              max_chunk_size_in_kb - maximum size of copy buffer in kbytes.
+@OUTPUT     : reshape_info - information describing the reshaping
+@RETURNS    : (nothing)
+@DESCRIPTION: Routine to set up reshaping information.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : May 26, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public void setup_reshaping_info(int icvid, int mincid, 
+                                 int do_norm, double fillvalue, int do_scalar,
+                                 char *axis_order[], Axis_ranges *axis_ranges,
+                                 long hs_start[], long hs_count[],
+                                 int max_chunk_size_in_kb,
+                                 Reshape_info *reshape_info)
+{
+   int input_ndims, input_dim[MAX_VAR_DIMS], order_dim[MAX_VAR_DIMS];
+   int output_ndims, norder;
+   int idim, jdim, ientry, iloop, order_idim;
+   int input_dim_used[MAX_VAR_DIMS];
+   char name[MAX_NC_NAME];
+   int *o2i, *i2o;
+   nc_type datatype;
+   int min_ndims, max_ndims, min_dim[MAX_VAR_DIMS], max_dim[MAX_VAR_DIMS];
+   int minid, maxid, dimid;
+   long total_size, size;
+   int nstart, ncount;
+   int has_vector_dimension;
+   int num_imgdims;
+   int fastest_input_img_dim, fastest_output_img_dim;
+   int no_chunk_dims_found;
+   long length;
+   long first, last;
+
+   /* Get input file dimension info */
+   (void) ncvarinq(mincid, ncvarid(mincid, MIimage), NULL, NULL, 
+                   &input_ndims, input_dim, NULL);
+   (void) ncdiminq(mincid, input_dim[input_ndims-1], name, NULL);
+   has_vector_dimension = (strcmp(name, MIvector_dimension) == 0);
+   fastest_input_img_dim = (has_vector_dimension ? 
+                            input_ndims-2 : input_ndims-1);
+   if (do_scalar && has_vector_dimension)
+      input_ndims--;
+   reshape_info->input_ndims = input_ndims;
+
+   /* Check length of hs_start and hs_count vectors */
+   for (nstart=0; (nstart<MAX_VAR_DIMS) && (hs_start[nstart]!=LONG_MIN); 
+        nstart++) {}
+   for (ncount=0; (ncount<MAX_VAR_DIMS) && (hs_count[ncount]!=LONG_MIN); 
+        ncount++) {}
+#if 0
+   if ((nstart != 0) && (ncount != 0) && (nstart != ncount)) {
+      (void) fprintf(stderr, 
+                     "Dimensions of start or count vectors not equal.\n");
+      exit(EXIT_FAILURE);
+   }
+#endif
+   if ((ncount > input_ndims) || (nstart > input_ndims)) {
+      (void) fprintf(stderr, 
+                     "Start and/or count vectors are too long.\n");
+      exit(EXIT_FAILURE);
+   }
+
+   /* Get start and count from file info and from hs_start and hs_count */
+   (void) miicv_inqint(icvid, MI_ICV_NUM_IMGDIMS, &num_imgdims);
+   for (idim=0; idim < input_ndims; idim++) {
+      (void) ncdiminq(mincid, input_dim[idim], NULL, 
+                      &reshape_info->input_size[idim]);
+      if ((idim > fastest_input_img_dim-num_imgdims) && 
+          (idim <= fastest_input_img_dim)) {
+         (void) miicv_inqlong(icvid, 
+                              MI_ICV_DIM_SIZE+fastest_input_img_dim-idim,
+                              &length);
+         if (length > 0) {
+            reshape_info->input_size[idim] = length;
+         }
+      }
+      if (idim < nstart)
+         reshape_info->input_start[idim] = hs_start[idim];
+      else
+         reshape_info->input_start[idim] = 0;
+      if (idim < ncount)
+         reshape_info->input_count[idim] = hs_count[idim];
+      else
+         reshape_info->input_count[idim] = reshape_info->input_size[idim];
+   }
+   
+   /* Get input dimension start and count from axis_ranges variable */
+   for (ientry=0; ientry < axis_ranges->nentries; ientry++) {
+      dimid = ncdimid(mincid, axis_ranges->name[ientry]);
+      for (idim=0; idim < input_ndims; idim++) {
+         if (dimid == input_dim[idim]) break;
+      }
+      if (idim >= input_ndims) {
+         (void) fprintf(stderr, "Unknown image dimension \"%s\"\n",
+                        axis_ranges->name[ientry]);
+         exit(EXIT_FAILURE);
+      }
+      reshape_info->input_start[idim] = axis_ranges->start[ientry];
+      reshape_info->input_count[idim] = axis_ranges->count[ientry];
+   }
+
+   /* Check to see if we will need a fill value */
+   reshape_info->need_fillvalue = FALSE;
+   for (idim=0; idim < input_ndims; idim++) {
+      first = reshape_info->input_start[idim];
+      last = first;
+      if (reshape_info->input_count[idim] > 0)
+         last += reshape_info->input_count[idim] - 1;
+      else if (reshape_info->input_count[idim] < 0)
+         last += reshape_info->input_count[idim] + 1;
+      if ((first < 0) || (first >= reshape_info->input_size[idim]) ||
+          (last < 0) || (last >= reshape_info->input_size[idim]))
+         reshape_info->need_fillvalue = TRUE;
+   }
+
+   /* Get output dimensions in terms of input */
+
+   /* Add up number of output dimensions */
+   output_ndims = 0;
+   for (idim=0; idim < input_ndims; idim++) {
+      if (reshape_info->input_count[idim] != 0) output_ndims++;
+   }
+   reshape_info->output_ndims = output_ndims;
+
+   /* Get dim ids for specified order */
+   for (norder=0; norder < MAX_VAR_DIMS+1; norder++) {
+      if (axis_order[norder] == NULL) break;
+      order_dim[norder] = ncdimid(mincid, axis_order[norder]);
+   }
+   if (norder > output_ndims) {
+      for (idim=0; idim < output_ndims; idim++) {
+         order_dim[idim] = order_dim[idim + norder - output_ndims];
+      }
+      norder = output_ndims;
+   }
+
+   /* Keep track of input dims already used in output (dimensions that
+      are disappearing are considered used) */
+   for (idim=0; idim < input_ndims; idim++) {
+      input_dim_used[idim] = (reshape_info->input_count[idim] == 0);
+   }
+
+   /* Re-order dimensions */
+   for (idim=output_ndims-1; idim >= 0; idim--) {    /* Output dim loop */
+      order_idim = idim - output_ndims + norder;
+      for (jdim=input_ndims-1; jdim >= 0; jdim--) {    /* Input dim loop */
+         /* For specified dimensions, look for corresponding input dim */
+         if (order_idim >= 0) {
+            if (input_dim[jdim] == order_dim[order_idim]) break;
+         }
+         /* For remaining dims, take next available */
+         else {
+            if (!input_dim_used[jdim]) break;
+         }
+      }
+      /* Check for error */
+      if ((jdim < 0) || input_dim_used[jdim]) {
+         if (order_idim >= 0) {
+            (void) fprintf(stderr, 
+      "Cannot re-order dimension \"%s\" (not found, repeated or removed).\n",
+                           axis_order[order_idim]);
+         }
+         else {
+            (void) fprintf(stderr, "Program error in re-ordering axes.\n");
+         }
+         exit(EXIT_FAILURE);
+      }
+      /* Save dimension mapping */
+      input_dim_used[jdim] = TRUE;
+      reshape_info->map_out_to_in[idim] = jdim;
+   }
+
+   /* Get mapping from input to output (-1 means no mapping) */
+   for (idim=0; idim < input_ndims; idim++) {
+      reshape_info->map_in_to_out[idim] = -1;
+   }
+   for (idim=0; idim < output_ndims; idim++) {
+      reshape_info->map_in_to_out[reshape_info->map_out_to_in[idim]] = idim;
+   }
+
+   /* Get fastest varying output image dimension (excluding vector dim) */
+   idim = input_dim[reshape_info->map_out_to_in[output_ndims-1]];
+   (void) ncdiminq(mincid, idim, name, NULL);
+   fastest_output_img_dim = ((strcmp(name, MIvector_dimension) == 0) ?
+                             output_ndims-2 : output_ndims-1);
+
+   /* Save dimensions used in blocks and chunks */
+   o2i = reshape_info->map_out_to_in;
+   i2o = reshape_info->map_in_to_out;
+   (void) miicv_inqint(reshape_info->icvid, MI_ICV_TYPE, (int *) &datatype);
+   total_size = nctypelen(datatype);
+   no_chunk_dims_found = TRUE;
+   for (idim=0; idim < output_ndims; idim++) {
+      reshape_info->dim_used_in_block[idim] = FALSE;
+      reshape_info->chunk_count[idim] = 1;
+   }
+   for (iloop=0; iloop < 6; iloop++) {
+      /* Go through possible dimensions in descending order of priority.
+         We start with the fastest varying dimension, but allow for the
+         possibility of vector dimensions in either volume (looping twice
+         on the same dimension is not a problem). Note that idim refers to
+         an output dimension. */
+      switch (iloop) {
+      case 0: idim = output_ndims-1; break;
+      case 1: idim = i2o[input_ndims-1]; break;
+      case 2: idim = fastest_output_img_dim; break;
+      case 3: idim = i2o[fastest_input_img_dim]; break;
+      case 4: idim = fastest_output_img_dim-1; break;
+      case 5: idim = i2o[fastest_input_img_dim-1]; break;
+      default: idim = -1;
+      }
+      if (idim != -1) size = ABS(reshape_info->input_count[o2i[idim]]);
+      else size = 0;
+      if (size == 0) idim = -1;
+      if ((idim != -1) && !reshape_info->dim_used_in_block[idim]) {
+         reshape_info->dim_used_in_block[idim] = TRUE;
+         if (no_chunk_dims_found ||
+             ((total_size * size) <= (max_chunk_size_in_kb * 1024))) {
+            no_chunk_dims_found = FALSE;
+            reshape_info->chunk_count[idim] = size;
+            total_size *= size;
+         }
+      }
+   }
+
+   /* Save fillvalue */
+   reshape_info->fillvalue = fillvalue;
+
+   /* Do we need to normalize to slices to a block min and max? */
+   if (do_norm) {
+      reshape_info->do_block_normalization = FALSE;
+   }
+   else {
+      reshape_info->do_block_normalization = FALSE;
+      
+      /* Loop through block dimensions and check if image-min/max varies
+         on the dimension */
+      ncopts = 0;
+      minid = ncvarid(mincid, MIimagemin);
+      maxid = ncvarid(mincid, MIimagemax);
+      ncopts = NCOPTS_DEFAULT;
+      if ((minid != MI_ERROR) && (maxid != MI_ERROR)) {
+         (void) ncvarinq(mincid, minid, NULL, NULL, &min_ndims, min_dim, NULL);
+         (void) ncvarinq(mincid, maxid, NULL, NULL, &max_ndims, max_dim, NULL);
+         for (idim=0; idim < input_ndims; idim++) {
+            jdim = reshape_info->map_out_to_in[idim];
+            if (reshape_info->dim_used_in_block[jdim]) {
+               dimid = input_dim[jdim];
+               for (jdim=0; jdim < min_ndims; jdim++) {
+                  if (min_dim[jdim] == dimid) {
+                     reshape_info->do_block_normalization = TRUE;
+                  }
+               }
+               for (jdim=0; jdim < max_ndims; jdim++) {
+                  if (max_dim[jdim] == dimid) {
+                     reshape_info->do_block_normalization = TRUE;
+                  }
+               }
+            }
+         }
+      }
+
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : setup_output_file
+@INPUT      : mincid - id of output minc file
+              history - string to be added to history list
+              reshape_info - information describing the reshaping
+@OUTPUT     : (none)
+@RETURNS    : (nothing)
+@DESCRIPTION: Routine to set up the output file
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : June 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public void setup_output_file(int mincid, char *history, 
+                              Reshape_info *reshape_info)
+{
+   int output_ndims, output_dim[MAX_VAR_DIMS];
+   int input_ndims, input_dim[MAX_VAR_DIMS];
+   int minmax_ndims, minmax_dim[MAX_VAR_DIMS];
+   int idim, odim, iloop;
+   int varid, icvid, imgid, varid2;
+   char dimname[MAX_NC_NAME];
+   long length;
+   int excluded_vars[2*MAX_VAR_DIMS + 10];
+   int nexcluded;
+   nc_type datatype;
+   char signtype[MI_MAX_ATTSTR_LEN];
+   double valid_range[2];
+   char *string;
+   int att_length;
+   int has_vector_dimension;
+   int fastest_img_dim;
+
+   /* Get useful info */
+   output_ndims = reshape_info->output_ndims;
+   (void) ncvarinq(reshape_info->inmincid, 
+                   ncvarid(reshape_info->inmincid, MIimage), 
+                   NULL, NULL, &input_ndims, input_dim, NULL);
+   input_ndims = reshape_info->input_ndims;
+
+   /* Check for vector dimension */
+   (void) ncdiminq(reshape_info->inmincid,
+                   input_dim[input_ndims-1], dimname, NULL);
+   has_vector_dimension = (strcmp(dimname, MIvector_dimension) == 0);
+   fastest_img_dim = (has_vector_dimension ? input_ndims-2 : input_ndims-1);
+
+   /* Create image dimensions */
+   for (odim=0; odim < output_ndims; odim++) {
+      idim = reshape_info->map_out_to_in[odim];
+      length = ABS(reshape_info->input_count[idim]);
+      (void) ncdiminq(reshape_info->inmincid, input_dim[idim], dimname, NULL);
+      output_dim[odim] = ncdimdef(mincid, dimname, length);
+   }
+
+   /* Copy all variables except dimensions and dimension widths */
+   ncopts = 0;
+   nexcluded = 0;
+   for (idim = 0; idim < input_ndims; idim++) {
+      (void) ncdiminq(reshape_info->inmincid, input_dim[idim], dimname, NULL);
+      if ((varid=ncvarid(reshape_info->inmincid, dimname)) != MI_ERROR)
+         excluded_vars[nexcluded++] = varid;
+      (void) strncat(dimname, DIM_WIDTH_SUFFIX, 
+                     sizeof(dimname)-strlen(dimname)-1);
+      if ((varid=ncvarid(reshape_info->inmincid, dimname)) != MI_ERROR)
+         excluded_vars[nexcluded++] = varid;
+   }
+   if ((varid=ncvarid(reshape_info->inmincid, MIimage)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+   if ((varid=ncvarid(reshape_info->inmincid, MIimagemax)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+   if ((varid=ncvarid(reshape_info->inmincid, MIimagemin)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+   (void) micopy_all_var_defs(reshape_info->inmincid, mincid, 
+                              nexcluded, excluded_vars);
+   ncopts = NCOPTS_DEFAULT;
+
+   /* Create image dimension variables */
+   for (odim=0; odim < output_ndims; odim++) {
+      idim = reshape_info->map_out_to_in[odim];
+      create_dim_var(mincid, output_dim[odim], 
+                     reshape_info->icvid,
+                     fastest_img_dim - idim,
+                     reshape_info->inmincid,
+                     reshape_info->input_start[idim],
+                     reshape_info->input_count[idim]);
+   }
+
+   /* Get basic image variable info */
+   icvid = reshape_info->icvid;
+   (void) miicv_inqint(icvid, MI_ICV_TYPE, (int *) &datatype);
+   (void) miicv_inqstr(icvid, MI_ICV_SIGN, signtype);
+   (void) miicv_inqdbl(icvid, MI_ICV_VALID_MIN, &valid_range[0]);
+   (void) miicv_inqdbl(icvid, MI_ICV_VALID_MAX, &valid_range[1]);
+
+   /* Set the valid range to include 0.0 for floating point if needed */
+   if (reshape_info->need_fillvalue &&
+       ((datatype == NC_FLOAT) || (datatype == NC_DOUBLE)) &&
+       (reshape_info->fillvalue == NOFILL)) {
+      if (0.0 < valid_range[0]) valid_range[0] = 0.0;
+      if (0.0 > valid_range[1]) valid_range[1] = 0.0;
+   }
+
+   /* Create the image variable */
+   imgid = micreate_std_variable(mincid, MIimage, datatype,
+                                 output_ndims, output_dim);
+   reshape_info->outimgid = imgid;
+   (void) micopy_all_atts(reshape_info->inmincid, 
+                          ncvarid(reshape_info->inmincid, MIimage),
+                          mincid, imgid);
+   (void) miattputstr(mincid, imgid, MIsigntype, signtype);
+   (void) ncattput(mincid, imgid, MIvalid_range, NC_DOUBLE, 2, valid_range);
+   (void) miattputstr(mincid, imgid, MIcomplete, MI_FALSE);
+
+   /* Create the imagemax/min variables */
+   minmax_ndims = 0;
+   for (odim=0; odim < output_ndims; odim++) {
+      if (!reshape_info->dim_used_in_block[odim]) {
+         minmax_dim[minmax_ndims++] = output_dim[odim];
+      }
+   }
+   for (iloop=0; iloop < 2; iloop++) {
+      if (iloop == 0)
+         string = MIimagemin;
+      else
+         string = MIimagemax;
+      varid = micreate_std_variable(mincid, string, NC_DOUBLE,
+                                    minmax_ndims, minmax_dim);
+      ncopts = 0;
+      varid2 = ncvarid(reshape_info->inmincid, string);
+      ncopts = NCOPTS_DEFAULT;
+      if (varid2 != MI_ERROR)
+         (void) micopy_all_atts(reshape_info->inmincid, 
+                                varid2, mincid, varid);
+   }
+
+   /* Add history */
+   ncopts=0;
+   if ((ncattinq(mincid, NC_GLOBAL, MIhistory, &datatype, &att_length) 
+        == MI_ERROR) || (datatype != NC_CHAR))
+      att_length = 0;
+   att_length += strlen(history) + 1;
+   string = MALLOC(att_length);
+   string[0] = '\0';
+   (void) miattgetstr(mincid, NC_GLOBAL, MIhistory, att_length, string);
+   ncopts = NCOPTS_DEFAULT;
+   (void) strcat(string, history);
+   (void) miattputstr(mincid, NC_GLOBAL, MIhistory, string);
+   FREE(string);
+
+   /* Get into data mode */
+   (void) ncsetfill(mincid, NC_NOFILL);
+   (void) ncendef(mincid);
+
+   /* Copy all the other data */
+   (void) micopy_all_var_values(reshape_info->inmincid, mincid,
+                                nexcluded, excluded_vars);
+
+   /* Copy the dimension variable values, if needed */
+   for (odim=0; odim < output_ndims; odim++) {
+      idim = reshape_info->map_out_to_in[odim];
+      copy_dimension_values(mincid, output_dim[odim], 
+                            reshape_info->inmincid,
+                            reshape_info->input_start[idim],
+                            reshape_info->input_count[idim]);
+   }
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : create_dim_var
+@INPUT      : outmincid - id of output minc file
+              outdimid - id of output dimension
+              inicvid - id of input icv
+              cur_image_dim - image dim number of current dimension in
+                 input icv (0 is fastest varying dimension)
+              inmincid - id of input minc file
+              input_start - start index of input dimension
+              input_count - count for input dimension (may be negative)
+@OUTPUT     : (none)
+@RETURNS    : (nothing)
+@DESCRIPTION: Creates a dimension variable and sets attributes properly.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : June 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public void create_dim_var(int outmincid, int outdimid,
+                           int inicvid, int cur_image_dim, int inmincid, 
+                           long input_start, long input_count)
+{
+   int invarid, outvarid;
+   int num_image_dims, var_ndims;
+   int is_regular, step_found, start_found, changed_spacing;
+   double dim_start, dim_step, icv_start, icv_step;
+   char dimname[MAX_NC_NAME];
+   char spacing[MAX_NC_NAME];
+
+   /* Get the dimension name */
+   (void) ncdiminq(outmincid, outdimid, dimname, NULL);
+
+   /* Get number of image dimensions */
+   (void) miicv_inqint(inicvid, MI_ICV_NUM_IMGDIMS, &num_image_dims);
+
+   /* Get step and start and spacing for dimension */
+   dim_step = 1.0;
+   dim_start = 0.0;
+   is_regular = TRUE;
+   changed_spacing = ((input_start != 0) || (input_count <= 0));
+   ncopts = 0;
+   invarid = ncvarid(inmincid, dimname);
+   if (invarid != MI_ERROR) {
+      step_found = (miattget1(inmincid, invarid, MIstep, NC_DOUBLE, 
+                              &dim_step) != MI_ERROR);
+      start_found = (miattget1(inmincid, invarid, MIstart, NC_DOUBLE, 
+                               &dim_start) != MI_ERROR);
+      (void) ncvarinq(inmincid, invarid, NULL, NULL, &var_ndims, NULL, NULL);
+      if (var_ndims > 0) {
+         (void) strcpy(spacing, MI_IRREGULAR);
+         (void) miattgetstr(inmincid, invarid, MIspacing, sizeof(spacing),
+                            spacing);
+         is_regular = (strcmp(spacing, MI_REGULAR) == 0);
+      }
+   }
+   ncopts = NCOPTS_DEFAULT;
+
+   /* Is the sampling changed because of the icv? */
+   if ((cur_image_dim < num_image_dims) && (cur_image_dim >= 0)) {
+      (void) miicv_inqdbl(inicvid, MI_ICV_DIM_STEP+cur_image_dim, &icv_step);
+      (void) miicv_inqdbl(inicvid, MI_ICV_DIM_START+cur_image_dim, &icv_start);
+      if ((icv_step != dim_step) || (icv_start != dim_start)) {
+         dim_step = icv_step;
+         dim_start = icv_start;
+         is_regular = TRUE;
+         changed_spacing = TRUE;
+      }
+   }
+
+   /* If spacing is not changed and the input variable does not exist don't
+      create the variable */
+   if (!changed_spacing && (invarid == MI_ERROR)) 
+      return;
+
+   /* Calculate the new dim_start and dim_step (if needed) */
+   dim_start += input_start * dim_step;
+   if (input_count < 0) dim_step = -dim_step;
+
+   /* Create the variable */
+   var_ndims = (is_regular ? 0 : 1);
+   ncopts = 0;
+   outvarid = micreate_std_variable(outmincid, dimname, NC_DOUBLE, 
+                                        var_ndims, &outdimid);
+   ncopts = NCOPTS_DEFAULT;
+   if (outvarid == MI_ERROR) {
+      outvarid = ncvardef(outmincid, dimname, NC_DOUBLE, var_ndims, &outdimid);
+   }
+   if (invarid != MI_ERROR)
+      (void) micopy_all_atts(inmincid, invarid, outmincid, outvarid);
+   if (is_regular || step_found)
+      (void) miattputdbl(outmincid, outvarid, MIstep, dim_step);
+   if (is_regular || start_found)
+      (void) miattputdbl(outmincid, outvarid, MIstart, dim_start);
+
+   /* Create width variable if needed */
+   ncopts = 0;
+   (void) strncat(dimname, DIM_WIDTH_SUFFIX, 
+                  sizeof(dimname)-strlen(dimname)-1);
+   invarid = ncvarid(inmincid, dimname);
+   if (invarid != MI_ERROR) {
+      (void) ncvarinq(inmincid, invarid, NULL, NULL, &var_ndims, NULL, NULL);
+      if (var_ndims > 0) var_ndims = 1;
+      outvarid = micreate_std_variable(outmincid, dimname, NC_DOUBLE, 
+                                           var_ndims, &outdimid);
+      if (outvarid == MI_ERROR) {
+         outvarid = ncvardef(outmincid, dimname, NC_DOUBLE, 
+                             var_ndims, &outdimid);
+      }
+      if (invarid != MI_ERROR)
+         (void) micopy_all_atts(inmincid, invarid, outmincid, outvarid);
+   }
+   ncopts = NCOPTS_DEFAULT;
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : copy_dimension_values
+@INPUT      : outmincid - id of output minc file
+              outdimid - id of output dimension
+              inmincid - id of input minc file
+              input_start - start index of input dimension
+              input_count - length of input dimension
+@OUTPUT     : (none)
+@RETURNS    : (nothing)
+@DESCRIPTION: Copies the data for a dimension variable.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : June 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public void copy_dimension_values(int outmincid, int outdimid, int inmincid,
+                                  long input_start, long input_count)
+{
+   char dimname[MAX_NC_NAME];
+   char varname[MAX_NC_NAME];
+
+   /* Get the dimension name */
+   (void) ncdiminq(outmincid, outdimid, dimname, NULL);
+   (void) strcpy(varname, dimname);
+
+   /* Copy the dimension coorindates */
+   copy_dim_var_values(outmincid, dimname, varname, inmincid,
+                       input_start, input_count);
+
+   /* Copy the dimension widths */
+   (void) strncat(varname, DIM_WIDTH_SUFFIX, 
+                  sizeof(varname)-strlen(varname)-1);
+   copy_dim_var_values(outmincid, dimname, varname, inmincid,
+                       input_start, input_count);
+
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : copy_dim_var_values
+@INPUT      : outmincid - id of output minc file
+              dimname - name of dimension
+              varname - name of variable to copy
+              inmincid - id of input minc file
+              input_start - start index of input dimension
+              input_count - length of input dimension
+@OUTPUT     : (none)
+@RETURNS    : (nothing)
+@DESCRIPTION: Copies the data for a dimension variable.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : June 16, 1994 (Peter Neelin)
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+public void copy_dim_var_values(int outmincid, char *dimname, char *varname,
+                                int inmincid,
+                                long input_start, long input_count)
+{
+   int invarid, outvarid;
+   int in_ndims, in_dim[MAX_VAR_DIMS], out_ndims;
+   char string[MAX_NC_NAME];
+   int good_data, is_width, flip_dimension;
+   long output_index, input_index, index, input_length;
+   double value, dim_width, dim_step, dim_start;
+
+   /* Do we need to copy data? */
+   ncopts = 0;
+   outvarid = ncvarid(outmincid, varname);
+   ncopts = NCOPTS_DEFAULT;
+   if (outvarid == MI_ERROR) return;
+   (void) ncvarinq(outmincid, outvarid, NULL, NULL, &out_ndims, NULL, NULL);
+   if (out_ndims != 1) return;
+
+   /* Is this a width variable? */
+   index = strlen(varname) - strlen(DIM_WIDTH_SUFFIX);
+   if (index < 0)
+      is_width = FALSE;
+   else
+      is_width = (strcmp(&varname[index], DIM_WIDTH_SUFFIX));
+
+   /* Check if there is a valid dimension variable from which to copy */
+   ncopts = 0;
+   invarid = ncvarid(inmincid, varname);
+   ncopts = NCOPTS_DEFAULT;
+   good_data = (invarid != MI_ERROR);
+   if (good_data) {
+      (void) ncvarinq(inmincid, invarid, NULL, NULL, &in_ndims, in_dim, NULL);
+      good_data = (in_ndims == 1);
+   }
+   if (good_data) {
+      (void) ncdiminq(inmincid, in_dim[0], string, &input_length);
+      good_data = (strcmp(string, dimname) == 0);
+   }
+
+   /* Get data from input file for estimating unknown values */
+   if (is_width) {       /* Get width for width variables */
+      dim_width = 0.0;
+      ncopts = 0;
+      (void) miattget1(inmincid, invarid, MIwidth, NC_DOUBLE, &dim_width);
+      ncopts = NCOPTS_DEFAULT;
+   }
+   else {                /* Get step and start for coordinate variables */
+      dim_step = 1.0;
+      dim_start = 0.0;
+      if (good_data) {
+         input_index = 0;
+         (void) mivarget1(inmincid, invarid, &input_index, NC_DOUBLE, NULL,
+                          &dim_start);
+         input_index = input_length - 1;
+         if (input_length <= 1) {
+            ncopts = 0;
+            (void) miattget1(inmincid, invarid, MIstep, NC_DOUBLE, &dim_step);
+            ncopts = NCOPTS_DEFAULT;
+         }
+         else {
+            (void) mivarget1(inmincid, invarid, &input_index, NC_DOUBLE, NULL,
+                             &value);
+            dim_step = (value - dim_start) / ((double) input_length - 1);
+         }
+      }
+      else {
+         ncopts = 0;
+         (void) miattget1(inmincid, invarid, MIstep, NC_DOUBLE, &dim_step);
+         (void) miattget1(inmincid, invarid, MIstart, NC_DOUBLE, &dim_start);
+         ncopts = NCOPTS_DEFAULT;
+      }
+      if (dim_step == 0.0) dim_step = 1.0;
+   }
+
+   /* Loop through output values */
+   flip_dimension = (input_count < 0);
+   input_count = ABS(input_count);
+   for (output_index=0; output_index < input_count; output_index++) {
+
+      /* Get input value */
+      if (!flip_dimension) {
+         input_index = input_start + output_index;
+      }
+      else {
+         input_index = input_start - output_index;
+      }
+      if (good_data && (input_index >= 0) && (input_index < input_length)) {
+         (void) mivarget1(inmincid, invarid, &input_index, NC_DOUBLE, NULL,
+                          &value);
+      }
+      else {
+         if (is_width) {
+            value = dim_width;
+         }
+         else {
+            value = input_index * dim_step + dim_start;
+         }
+      }
+      (void) mivarput1(outmincid, outvarid, &output_index, NC_DOUBLE, NULL,
+                       &value);
+
+   }
+
+}
+
new file mode 100644
--- /dev/null
+++ b/progs/mincreshape/mincreshape.h
@@ -0,0 +1,150 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : mincreshape.h
+@DESCRIPTION: Header file for mincreshape.c
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    : March 11, 1994 (Peter Neelin)
+@MODIFIED   : $Log: mincreshape.h,v $
+@MODIFIED   : Revision 1.1  1994-11-02 16:22:00  neelin
+@MODIFIED   : Initial revision
+@MODIFIED   :
+@COPYRIGHT  :
+              Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre, 
+              Montreal Neurological Institute, McGill University.
+              Permission to use, copy, modify, and distribute this
+              software and its documentation for any purpose and without
+              fee is hereby granted, provided that the above copyright
+              notice appear in all copies.  The author and McGill University
+              make no representations about the suitability of this
+              software for any purpose.  It is provided "as is" without
+              express or implied warranty.
+---------------------------------------------------------------------------- */
+
+/* Constants used in program */
+#define NOFILL DBL_MAX   /* Fillvalue indicating -nofill */
+#define FILL -DBL_MAX    /* Fillvalue for -fill */
+#define NCOPTS_DEFAULT NC_VERBOSE | NC_FATAL
+#define DEFAULT_MAX_CHUNK_SIZE_IN_KB (1024*4)
+#define DIM_WIDTH_SUFFIX "-width"
+#define VECTOR_SEPARATOR ','
+#ifndef TRUE
+#  define TRUE 1
+#  define FALSE 0
+#endif
+
+/* Types used in program */
+
+typedef struct {
+   int verbose;
+   int icvid, inmincid, outmincid, outimgid;
+   nc_type output_datatype;
+   int output_is_signed;
+   int input_ndims;                  /* Number of input dimensions */
+   int output_ndims;                 /* Number of output dimensions */
+   long input_size[MAX_VAR_DIMS];    /* Size of input volume */
+   long input_start[MAX_VAR_DIMS];   /* Start of desired hyperslab */
+   long input_count[MAX_VAR_DIMS];   /* Size of desired hyperslab 
+                                        (<0 means 1 and remove dimension) */ 
+   int map_out_to_in[MAX_VAR_DIMS];  /* Map output dimension index to input */
+   int map_in_to_out[MAX_VAR_DIMS];  /* Map input dimension index to output
+                                        (-1 means no mapping) */
+   int dim_used_in_block[MAX_VAR_DIMS]; /* TRUE if output dim used in block */
+   int chunk_count[MAX_VAR_DIMS];    /* Specifies count for chunk hyperslab */
+   int need_fillvalue;               /* TRUE if we will need a fill value */
+   double fillvalue;                 /* Value to fill with (FILL_DEFAULT
+                                        means fill with real value zero) */
+   int do_block_normalization;       /* Normalize slices to block max/min */
+
+   /* Note that a block is a hyperslab of the output volume in which all
+      values are normalized the same way. A chunk is a hyperslab that is
+      copied in one piece (smaller than or equal to a block). */
+
+} Reshape_info;
+
+typedef struct {
+   int nentries;
+   char *name[MAX_VAR_DIMS];
+   long size[MAX_VAR_DIMS];
+} Dimsize_list;
+
+typedef struct {
+   int nentries;
+   char *name[MAX_VAR_DIMS];
+   long start[MAX_VAR_DIMS];
+   long count[MAX_VAR_DIMS];
+} Axis_ranges;
+
+/* Macros used in program */
+#define ISSPACE(ch) (isspace((int)ch))
+#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
+#define  MAX( x, y )  ( ((x) >= (y)) ? (x) : (y) )
+#define  MIN( x, y )  ( ((x) <= (y)) ? (x) : (y) )
+
+/* Function prototypes */
+public int main(int argc, char *argv[]);
+public void get_arginfo(int argc, char *argv[],
+                        Reshape_info *reshape_info);
+public int get_fillvalue(char *dst, char *key, char *nextArg);
+public int get_dimsize(char *dst, char *key, char *nextArg);
+public int get_axis_order(char *dst, char *key, char *nextArg);
+public int get_axis_range(char *dst, char *key, char *nextArg);
+public int get_arg_vector(char *dst, char *key, char *nextArg);
+public void get_default_datatype(int mincid, nc_type *datatype, int *is_signed,
+                                 double valid_range[2]);
+public void setup_dim_sizes(int icvid, int mincid, Dimsize_list *dimsize_list);
+public void setup_reshaping_info(int icvid, int mincid, 
+                                 int do_norm, double fillvalue, int do_scalar,
+                                 char *axis_order[], Axis_ranges *axis_ranges,
+                                 long hs_start[], long hs_count[],
+                                 int max_chunk_size_in_kb,
+                                 Reshape_info *reshape_info);
+public void setup_output_file(int mincid, char *history, 
+                              Reshape_info *reshape_info);
+public void create_dim_var(int outmincid, int outdimid,
+                           int inicvid, int cur_image_dim, int inmincid, 
+                           long input_start, long input_count);
+public void copy_dimension_values(int outmincid, int outdimid, int inmincid,
+                                  long input_start, long input_count);
+public void copy_dim_var_values(int outmincid, char *dimname, char *varname,
+                                int inmincid,
+                                long input_start, long input_count);
+public void copy_data(Reshape_info *reshape_info);
+public void get_num_minmax_values(Reshape_info *reshape_info,
+                                  long *block_start, long *block_count,
+                                  long *num_min_values, long *num_max_values);
+public void handle_normalization(Reshape_info *reshape_info,
+                                 long *block_start,
+                                 long *block_count,
+                                 double *minmax_buffer,
+                                 double *fillvalue);
+public void truncate_input_vectors(Reshape_info *reshape_info,
+                                   long *input_start,
+                                   long *input_count);
+public void translate_output_to_input(Reshape_info *reshape_info,
+                                      long *output_start,
+                                      long *output_count,
+                                      long *input_start,
+                                      long *input_count);
+public void translate_input_to_output(Reshape_info *reshape_info,
+                                      long *input_start,
+                                      long *input_count,
+                                      long *output_start,
+                                      long *output_count);
+public void copy_the_chunk(Reshape_info *reshape_info,
+                           long chunk_start[],
+                           long chunk_count[],
+                           void *chunk_data,
+                           double fillvalue);
+public void convert_value_from_double(double dvalue, 
+                                      nc_type datatype, int is_signed,
+                                      void *ptr);
+public void nd_begin_looping(long start[], long current[], int ndims);
+public int nd_end_of_loop(long start[], long end[], int ndims);
+public void nd_update_current_count(long current[], 
+                                    long increment[], long end[],
+                                    long current_count[],
+                                    int ndims);
+public void nd_increment_loop(long current[], 
+                              long start[], long increment[], long end[],
+                              int ndims);
new file mode 100644
--- /dev/null
+++ b/progs/mincreshape/mincreshape.man1
@@ -0,0 +1,347 @@
+.\" Copyright 1994 Peter Neelin, McConnell Brain Imaging Centre,
+.\" Montreal Neurological Institute, McGill University.
+.\" Permission to use, copy, modify, and distribute this
+.\" software and its documentation for any purpose and without
+.\" fee is hereby granted, provided that the above copyright
+.\" notice appear in all copies.  The author and McGill University
+.\" make no representations about the suitability of this
+.\" software for any purpose.  It is provided "as is" without
+.\" express or implied warranty.
+.\"
+.\" $Header: /private-cvsroot/minc/progs/mincreshape/mincreshape.man1,v 1.1 1994-11-02 16:22:08 neelin Exp $
+.\"
+.TH MINCRESHAPE 1 "MINC Image File Format"
+
+.SH NAME
+mincreshape - cuts a hyperslab out of a minc file (with dimension re-ordering)
+
+.SH SYNOPSIS
+.B mincreshape
+[<options>] <infile>.mnc <outfile>.mnc
+
+.SH DESCRIPTION 
+.I Mincreshape's
+main job is to chop a hyperslab out of a minc file and put it into a
+new minc file. "What is a hyperslab?", you ask. It is simply a
+multi-dimensional box specified with a starting index (a vector giving
+a voxel coordinate) and a count vector (a number of voxels along each
+axis). A single slice out of a volume is a hyperslab (with a count of
+1 in the slice direction), a small block pulled out of a large volume
+is a hyperslab, a single echo volume out of a multi-echo MRI dataset
+is a hyperslab, one time point out of a dynamic acquisition is a
+hyperslab - you get the idea.  Check out the -start, -count and
+-dimrange options for more details on how to do this (and look at the
+examples!). If you are pulling out only one point along a dimension,
+you have the option of making the dimension disappear, so mincreshape
+gives you the ability to reduce the dimensionality of a minc file. As
+well, you aren't constrained to specify a hyperslab that is only
+within the input file, you can extend beyond the bounds of the
+dimensions in the input file, and furthermore you can give a count
+that will flip the data along a dimension.
+
+As if all that is not enough
+.I mincreshape
+has the ability to re-order dimensions. The most obvious case is
+converting a transverse image into a coronal image. But you can
+type a list of dimension names to get an arbitrary order of
+dimensions.
+
+You want more!?! Okay, okay.
+.I mincreshape
+makes all of the minc library icv conversions available on the command
+line. The include changing type, range and normalization of the pixel
+values, expanding or contracting images (by pixel duplication or
+averaging) to give a specified image size, and converting vector
+images to scalar.
+
+Just so you don't get confused let me tell you clearly here:
+.I Mincreshape
+does all of the icv conversions first and then the hyperslab and
+dimension re-ordering stuff is applied to the result of that. So if
+you want to mix them together (like -imgsize, -start, -count), get it
+clear in your head first.
+
+Okay, hold on to your seat: here's a list of options.
+
+.SH OPTIONS
+Note that options can be specified in abbreviated form (as long as
+they are unique) and can be given anywhere on the command line.
+
+.SH General options
+.P
+.I -clobber:
+Overwrite an existing file.
+.P
+.I -noclobber:
+Don't overwrite an existing file (default).
+.P
+.I -verbose:
+Print out progress information for each chunk of data copied
+(default). A chunk varies in size depending mostly on whether you're
+re-ordering dimensions or not and how big the internal buffer is
+allowed to be.
+.P
+.I -quiet:
+Do not print out progress information.
+.P
+.I -max_chunk_size_in_kb:
+Specify the maximum size of the copy buffer (in kbytes). Default is
+4096 kbytes.
+
+.SH Image conversion options (pixel type and range):
+The default for type, sign and valid range is to use those of the input
+file. If type is specified, then both sign and valid range are set to
+the default for that type. If sign is specified, then valid range is
+set to the default for the type and sign.
+.P
+.I -filetype:
+Don't do any type conversion (default).
+.P
+.I -byte:
+Write out bytes values.
+.P
+.I -short:
+Write out short integer values.
+.P
+.I -long:
+Write out long integer values.
+.P
+.I -float:
+Write out single-precision floating point values.
+.P
+.I -double:
+Write out double-precision floating point values.
+.P
+.I -signed:
+Write out values as signed integers (default for short and long). Ignored for
+floating point types.
+.P
+.I -unsigned:
+Write out values as unsigned integers (default for byte). Ignored for
+floating point types.
+.P
+.I -valid_range 
+<min> <max>:
+specifies the valid range of output voxel values in their integer
+representation. Default is the full range
+for the type and sign. This option is ignored for floating point
+values.
+.P
+.I -image_range:
+<min> <max>
+Normalize images to a given minimum and maximum real value (not voxel
+value).
+.P
+.I -normalize:
+Normalize images to real minimum and maximum for the entire input
+file.
+.P
+.I -nonormalize:
+Do not normalize images (default).
+.P
+.I -nopixfill:
+Do not convert out-of-range values in input file, just copy them
+through.
+.P
+.I -pixfill:
+Replace out-of-range values in input file by the smallest possible
+value (default). 
+.P
+.I -pixfillvalue
+<value>:
+Specify a new pixel value to replace out-of-range values in the input
+file.
+
+.SH Image conversion options (dimension direction and size):
+.P
+.I -scalar:
+Convert vector images to scalar images (a vector image is one with
+vector_dimension as the fastest varying dimension). The vector
+dimension is removed and values are averaged.
+.P
+.I -noscalar:
+Do not convert vector images to scalar images (default).
+.P
+.I +direction:
+Flip images to give positive step value for spatial axes.
+Note that the flipping of spatial axes only applies to "image
+dimensions". These are the two fastest varying (non-vector) dimensions
+in the file. If you want to flip a non-image dimension, you can
+convert it to an image dimension with -dimsize <dimname>=-1 (the -1
+means don't really change the size). Check out the examples.
+.P
+.I -direction:
+Flip images to give negative step value for spatial axes.
+.P
+.I -anydirection:
+Don't flip images along spatial axes (default).
+.P
+.I +xdirection:
+Flip images to give positive xspace:step value (left-to-right).
+.P
+.I -xdirection:
+Flip images to give negative xspace:step value (right-to-left).
+.P
+.I -xanydirection:
+Don't flip images along x-axis.
+.P
+.I +ydirection:
+Flip images to give positive yspace:step value (posterior-to-anterior).
+.P
+.I -ydirection:
+Flip images to give negative yspace:step value (anterior-to-posterior).
+.P
+.I -yanydirection:
+Don't flip images along y-axis.
+.P
+.I +zdirection:
+Flip images to give positive zspace:step value (inferior-to-superior).
+.P
+.I -zdirection:
+Flip images to give negative zspace:step value (superior-to-inferior).
+.P
+.I -zanydirection:
+Don't flip images along z-axis.
+.P
+.I -keepaspect:
+Preserve aspect ratio when resizing images. This means that voxels are
+replicated (or averaged) the same number of times along each image
+dimension.
+.P
+.I -nokeepaspect:
+Do not force preservation of aspect ratio when resizing images (default).
+.P
+.I -imgsize
+<size>:
+Specify the desired image size (used if -rowsize or -colsize not
+given).
+.P
+.I -rowsize
+<size>:
+Specify the desired number of rows in the image.
+.P
+.I -colsize
+<size>:
+Specify the desired number of columns in the image.
+.P
+.I -dimsize
+<dimension>=<size>
+Specify the size of a named dimension (<dimension>=<size>). Note that
+the resizing only applies to "image dimensions" - usually the two
+fastest-varying (non-vector) dimensions. To do dimension resizing, all
+fastest-varying dimensions up to the named dimension are turned into
+image dimensions, and these are then affected by the direction
+options. The dimension name and size must be in one command-line
+argument, so if you use spaces (which is okay), remember to use quotes
+to hide them from the shell.
+
+.SH Reshaping options:
+.P
+.I -transverse:
+Write out transverse slices.
+.P
+.I -sagittal:
+Write out sagittal slices.
+.P
+.I -coronal:
+Write out coronal slices.
+.P
+.I -dimorder
+<dim1>,<dim2>,<dim3>,...:
+Specify dimension order, where <dim?> are the names of the dimensions.
+You can give fewer dimensions than exist in the file: they are assumed
+to be the fastest varying dimensions in the output file (so
+-transverse is exactly equivalent to -dimorder zspace,yspace,xspace).
+Again, spaces are allowed between names, but remember to hide them
+from the shell with quotes.
+.P
+.I -dimrange
+<dim>=<start>[,<count>]:
+Specify the range of dimension subscripts for dimension <dim>. If
+<count> is missing or 0, then it is taken to mean 1, but remove the
+dimension from the output file (a count of 1 will keep a dimension of
+size 1). A negative <count> means flip the data along that dimension -
+in this case <start> specifies the highest voxel coordinate for the
+dimension (-dimrange xspace=3,-3 gives a flipped version of -dimrange
+xspace=1,3). The options -start and -count provide an alternative way
+to specify the same information.
+.P
+.I -start
+<coord0>,<coord1>,<coord2>,...:
+Specifies the starting corner of the hyperslab (coordinates go from
+slowest varying dimension to fastest). If fewer coordinates are given than
+dimensions exist in the file, then they are assumed to apply
+to the slowest varying dimensions and the remaining coordinates are
+set to 0. See -dimrange for more details.
+.P
+.I -count
+<size0>,<size1>,<size2>,...:
+Specifies edge lengths of hyperslab to read (coordinates go from
+slowest varying dimension to fastest). If fewer sizes are given than 
+dimensions exist in the file, then they are assumed to apply to the
+slowest varying dimensions and the remaining sizes are set to the full
+size of the dimension. See -dimrange for more details.
+
+.SH Missing data options:
+.P
+.I -nofill:
+Use value zero for points outside of the input volume (default).
+.P
+.I -fill:
+Use a fill value for points outside of input volume (minimum possible
+value).
+.P
+.I -fillvalue
+<fillvalue>:
+Specify a fill value for points outside of the input volume (this is a
+real value, not a pixel value).
+
+.SH Generic options for all commands:
+.P
+.I -help:
+Print summary of command-line options and abort.
+
+.SH EXAMPLES:
+
+Assume that we have a volume with dimensions zspace,yspace,xspace and
+sizes 128,256,256. If we want to get slice 40 out of it (keeping the
+coordinate information for the zspace dimension), then we can use
+     mincreshape original.mnc new.mnc \\
+           -dimrange zspace=40,1
+
+Alternatively, we could use
+     mincreshape original.mnc new.mnc \\
+           -start 40,0,0 -count 1,256,256
+
+Or simply
+     mincreshape original.mnc new.mnc \\
+           -start 40 -count 1
+
+If we wanted to get rid of the zspace dimension, we could use
+     mincreshape original.mnc new.mnc \\
+           -dimrange zspace=40,0
+
+Let's get a block out of the middle and flip it along xspace:
+     mincreshape original.mnc new.mnc \\
+           -start 40,10,240 -count 1,200,-200
+
+But why restrain outselves? Let's go out of bounds:
+     mincreshape original.mnc new.mnc \\
+           -start 40,-100,340 -count 1,200,-200
+
+How about some sideways heads - flip x and y. And convert to byte to
+save space while we're at it:
+     mincreshape original.mnc new.mnc \\
+           -dimorder xspace,yspace -byte
+
+Let's make sure that all dimensions have a negative step attribute
+(see option +direction for some details):
+     mincreshape original.mnc new.mnc \\
+           -direction -dimsize zspace=-1
+
+.SH AUTHOR
+Peter Neelin
+
+.SH COPYRIGHTS
+.ps 18
+\fB\(co\fR\s12 Copyright 1994 by Peter Neelin