view libsrc2/dimension.c @ 1722:f512ca3023db

*** empty log message ***
author baghdadi <baghdadi>
date Thu, 01 Apr 2004 00:47:21 +0000 (2004-04-01)
parents e864a428b34f
children 2b0402e87958
line wrap: on
line source
/** \file dimension.c
 * \brief MINC 2.0 "dimension" functions
 ************************************************************************/
#include <stdlib.h>
#include <hdf5.h>
#include "minc2.h"
#include "minc2_private.h"
#include "minc.h"


/*! Figure out whether a dimension is associated with a volume.
 */

int 
miget_volume_from_dimension(midimhandle_t dimension, mihandle_t *volume)
{
 
  if (dimension == NULL) {
    return (MI_ERROR);
  }  

  if (dimension->volume_handle != NULL) {
    
    *volume = dimension->volume_handle;
  }
  else {
    return (MI_ERROR);
  }

  return (MI_NOERROR);
}

/*! Create a copy of a given dimension.
 */

int 
micopy_dimension(midimhandle_t dim_ptr, midimhandle_t *new_dim_ptr)
{
  int i;
  dimension *handle;
  
  if (dim_ptr == NULL) {
    return (MI_ERROR);
  }

  /* Allocate storage for the structure
   */
  handle = (dimension *)malloc(sizeof(*handle));
  if (handle == NULL) {
    return (MI_ERROR);
  }
  handle->attr = dim_ptr->attr;
  handle->class = dim_ptr->class;
  /* Copy direction cosines */
  handle->direction_cosines[MI2_X] = dim_ptr->direction_cosines[0];
  handle->direction_cosines[MI2_Y] = dim_ptr->direction_cosines[1];
  handle->direction_cosines[MI2_Z] = dim_ptr->direction_cosines[2];
 
  switch (dim_ptr->flipping_order) {
  case MI_FILE_ORDER:
    handle->flipping_order = MI_FILE_ORDER;
    break;
  case MI_COUNTER_FILE_ORDER:
    handle->flipping_order = MI_COUNTER_FILE_ORDER;
    break;
  default:
    return (MI_ERROR);
  }
  
  handle->name =strdup(dim_ptr->name);
  handle->length = dim_ptr->length;
  if (dim_ptr->offsets != NULL) {
    handle->offsets = (double *) malloc(dim_ptr->length*sizeof(double));
    if (handle->offsets == NULL) {
      return (MI_ERROR);
    }
    for (i=0; i < dim_ptr->length; i++) {
      handle->offsets[i] = dim_ptr->offsets[i];
    }
  }
  else {
    handle->offsets = NULL;
  }
  handle->start = dim_ptr->start;
  handle->step = dim_ptr->step;
  if (dim_ptr->units != NULL) {
    handle->units = strdup(dim_ptr->units);
  }
  else {
    handle->units = NULL;
  }
  handle->width = dim_ptr->width;
  if (dim_ptr->widths != NULL) {
    handle->widths = (double *) malloc(dim_ptr->length*sizeof(double));
    if (handle->widths == NULL) {
      return (MI_ERROR);
    }
    for (i=0; i < dim_ptr->length; i++) {
      handle->widths[i] = dim_ptr->widths[i];
    }
  }
  else {
    handle->widths = NULL;
  }
  handle->volume_handle = dim_ptr->volume_handle;

  *new_dim_ptr = handle;
  
  return (MI_NOERROR);
}

/*! Define a new dimension in a MINC volume.
 */

int 
micreate_dimension(const char *name, midimclass_t class, midimattr_t attr, 
		   unsigned long length, midimhandle_t *new_dim_ptr)
{  
  
  dimension *handle;
  int i;
  /* Allocate space for the new dimension
   */
  handle = (dimension *)malloc(sizeof(*handle));
  if (handle == NULL) {
    return (MI_ERROR);
  }


  /* Duplicate the dimension name
   */
  handle->name = strdup(name);
  /* Set the dimension comment to NULL unless otherwise
   */
  handle->comments = NULL;  
  switch (class) {
  case MI_DIMCLASS_SPATIAL:
    handle->class  = MI_DIMCLASS_SPATIAL;
    if (strcmp(name, "xspace") == 0) {
      handle->direction_cosines[MI2_X] = 1.0;
      handle->direction_cosines[MI2_Y] = 0.0;
      handle->direction_cosines[MI2_Z] = 0.0;
      handle->comments = strdup("X increases from patient left to right");
    }
    else if (strcmp(name, "yspace") == 0) {
      handle->direction_cosines[MI2_X] = 0.0;
      handle->direction_cosines[MI2_Y] = 1.0;
      handle->direction_cosines[MI2_Z] = 0.0;
      handle->comments = strdup("Y increases from patient posterior to anterior");
    }
    else if (strcmp(name, "zspace") == 0) {
      handle->direction_cosines[MI2_X] = 0.0;
      handle->direction_cosines[MI2_Y] = 0.0;
      handle->direction_cosines[MI2_Z] = 1.0;
      handle->comments = strdup("Z increases from patient inferior to superior");
    }
    else {
      handle->direction_cosines[MI2_X] = 1.0;
      handle->direction_cosines[MI2_Y] = 0.0;
      handle->direction_cosines[MI2_Z] = 0.0;
      handle->comments = NULL;
    }
    break;
  case MI_DIMCLASS_TIME:
    handle->class  = MI_DIMCLASS_TIME;
    break;
  case MI_DIMCLASS_SFREQUENCY:
    handle->class  = MI_DIMCLASS_SFREQUENCY;
    if (strcmp(name, "xfrequency") == 0) {
      handle->direction_cosines[MI2_X] = 1.0;
      handle->direction_cosines[MI2_Y] = 0.0;
      handle->direction_cosines[MI2_Z] = 0.0;
    }
    else if (strcmp(name, "yfrequency") == 0) {
      handle->direction_cosines[MI2_X] = 0.0;
      handle->direction_cosines[MI2_Y] = 1.0;
      handle->direction_cosines[MI2_Z] = 0.0;
    }
    else if (strcmp(name, "zfrequency") == 0) {
      handle->direction_cosines[MI2_X] = 0.0;
      handle->direction_cosines[MI2_Y] = 0.0;
      handle->direction_cosines[MI2_Z] = 1.0;
    }
    else {
      handle->direction_cosines[MI2_X] = 1.0;
      handle->direction_cosines[MI2_Y] = 0.0;
      handle->direction_cosines[MI2_Z] = 0.0;
    }
    break;
  case MI_DIMCLASS_TFREQUENCY:
    handle->class  = MI_DIMCLASS_TFREQUENCY;
    break;
  case MI_DIMCLASS_USER:
    handle->class  = MI_DIMCLASS_USER;
    break;
  case MI_DIMCLASS_RECORD:
    handle->class  = MI_DIMCLASS_RECORD;
    break;
  case MI_DIMCLASS_ANY:
  default:
    return (MI_ERROR);
  }

  handle->offsets = NULL;
  handle->attr = attr;
  if (attr & MI_DIMATTR_NOT_REGULARLY_SAMPLED) {
    handle->widths = (double *) malloc(length *sizeof(double));
    for (i=0; i< length; i++) {
      
      handle->widths[i] = 1.0;
    }
  }
  else {
    handle->widths = NULL;
  }
  handle->start = 0.0;
  handle->step = 1.0;
  handle->width = 1.0;

  handle->flipping_order = MI_FILE_ORDER;
  if (class != MI_DIMCLASS_SPATIAL && class != MI_DIMCLASS_SFREQUENCY ) {
    handle->direction_cosines[MI2_X] = 1.0;
    handle->direction_cosines[MI2_Y] = 0.0;
    handle->direction_cosines[MI2_Z] = 0.0;
  }
  handle->length = length;
  handle->units = strdup("mm");
  /* volume_handle is the only NULL value once the dimension is created.
   */
  handle->volume_handle = NULL;

  *new_dim_ptr = handle;
  
  return (MI_NOERROR);

}

/*! Delete the dimension definition.
    Note: The original document stated that a dimension has to be
    associated with a given volume before it can be deleted. This
    feature was erased from the document and not considered here.
 */
int 
mifree_dimension_handle(midimhandle_t dim_ptr)
{
  
  if (dim_ptr == NULL) {
    return (MI_ERROR);
  }
  if (dim_ptr->name != NULL) {
      free(dim_ptr->name);
  }
  if (dim_ptr->offsets != NULL) {
    free(dim_ptr->offsets);
  }
  if (dim_ptr->units != NULL) {
      free(dim_ptr->units);
  }
  if (dim_ptr->widths !=NULL) {
    free(dim_ptr->widths);
  }
  free(dim_ptr);
  
  return (MI_NOERROR);
}

/** Retrieve the list of dimensions defined in a MINC volume, 
 *  with the same class \a class and attribute \a attr.
 * \retval The number of dimensions returned.
 * \retval MI_ERROR on failure.
 */
int 
miget_volume_dimensions(mihandle_t volume, midimclass_t class, midimattr_t attr,
			miorder_t order, int array_length, 
			midimhandle_t dimensions[])
{
  // THE PARAMETER "miorder_t order" WAS NOT CONSIDERED WHEW WRITING
  // THIS FUNCTION. MUST FIGURE OUT WHAT TO DO WITH IT
  
  hsize_t number_of_dims; 
  int i=0, max_dims;
  int num_ret_dims = 0;
  
  if (volume == NULL) {
    return (MI_ERROR);
  }
 
  number_of_dims = volume->number_of_dims;

  if (array_length > number_of_dims) {
    max_dims = number_of_dims;
  }
  else {
    max_dims = array_length;
  }
  
  /* Go through each dimension separately and figure out
     which one has a matching class and attirbute.
   */
  for (i=0; i < max_dims; i++) {
      midimhandle_t hdim = volume->dim_handles[i];
      if (class == MI_DIMCLASS_ANY || class == hdim->class) {
          if (hdim->attr == attr || attr ==  MI_DIMATTR_ALL) {
              dimensions[num_ret_dims++] = hdim;
          }
      }
  }
  return (num_ret_dims);
}

/*! Set apparent dimension order.
 */

int 
miset_apparent_dimension_order(mihandle_t volume, int array_length, 
			       midimhandle_t dimensions[])
{
  int diff;
  int i=0, j=0, k=0;

  if (volume == NULL || array_length <= 0 || 
      array_length != volume->number_of_dims) {
    return (MI_ERROR);
  }
   /* If array_length was more than the number of dimensions
     the rest of the given dimensions will be ignored.
   */ 
  diff = volume->number_of_dims - array_length;
  if (diff < 0) {
    diff = 0;
  }
  /* Allocated space for dimensions indices, if not already done.
   */
  if (volume->dim_indices == NULL){
    volume->dim_indices = (int *)malloc(volume->number_of_dims*sizeof(int));
    memset(volume->dim_indices, -1, sizeof(volume->number_of_dims));
  }
  for (i=0; i < volume->number_of_dims; i++) {
    for (j=0; j < array_length; j++) {
      if (volume->dim_handles[i] == dimensions[j]) {
	volume->dim_indices[j+diff] = i;
	break;
      }
      if (j == (array_length-1)) {
	volume->dim_indices[k++] = i;
      }
    }
  }
  return (MI_NOERROR);
}

/*! Set apparent dimension order by name.
 */

int 
miset_apparent_dimension_order_by_name(mihandle_t volume, int array_length, 
				       char **names)
{
  int diff;
  int i=0, j=0, k=0;

  if (volume == NULL) {
    return (MI_ERROR);
  }

  if (names == NULL || array_length <= 0) {
      /* Reset the dimension ordering */
      if (volume->dim_indices != NULL) {
          free(volume->dim_indices);
          volume->dim_indices = NULL;
      }
      return (MI_NOERROR);
  }

  /* Note that all dimension names must be different or an error occurs.
   */
  for (i = 0; i < array_length; i++) {
    for (j = i + 1; j < array_length; j++) {
      if (strcmp(names[i], names[j]) == 0) {
	return (MI_ERROR);
      }
    }
  }
  /* If array_length was more than the number of dimensions
     the rest of the given dimensions will be ignored.
   */ 
  diff = volume->number_of_dims - array_length;
  if (diff < 0) {
      diff = 0;
  }
  /* Allocated space for dimensions indices, if not already done.
   */
  if (volume->dim_indices == NULL) {
      volume->dim_indices = (int *)malloc(volume->number_of_dims*sizeof(int));
      for (i = 0; i < volume->number_of_dims; i++) {
          volume->dim_indices[i] = -1;
      }
  }
  for (i = 0; i < volume->number_of_dims; i++) {
      for (j = 0; j < array_length; j++) {
          if (!strcmp(volume->dim_handles[i]->name, names[j])) {
              volume->dim_indices[i+diff] = j;
              break;
          }
      }
      if (j == (array_length-1)) {
          volume->dim_indices[k++] = i;
      }
  }
  return (MI_NOERROR);
}

/*! Set the record flag and add a record dimension to the volume
    dimensions so the volume wuld appear to have n+1 dimensions
 */

int 
miset_apparent_record_dimension_flag(mihandle_t volume, int record_flag)
{
  
  dimension *handle;  
 
  if (volume == NULL) {
    return (MI_ERROR);
  }
  /* Allocate space for the dimension
   */
  handle = (dimension *)malloc(sizeof(*handle));
  if (handle == NULL) {
    return (MI_ERROR);
  }
  handle->class = MI_DIMCLASS_RECORD;
  handle->volume_handle = volume;

  volume->dim_handles[volume->number_of_dims] = handle;
  /* Add one to the number of dimensions so the volume
     will appear to have (n+1) dimensions
   */
  volume->number_of_dims++;
  
  record_flag = 1;

  return (MI_NOERROR);
}

/*! Get the apparent order of voxels.
 */

int 
miget_dimension_apparent_voxel_order(midimhandle_t dimension, miflipping_t *file_order,
				     miflipping_t *sign)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  switch (dimension->flipping_order) {
  case MI_FILE_ORDER:
    *file_order = MI_FILE_ORDER;
    if (dimension->step > 0) {
      *sign = MI_POSITIVE;
    }
    else {
      *sign = MI_NEGATIVE;
    }
    break;
  case MI_COUNTER_FILE_ORDER:
    *file_order = MI_COUNTER_FILE_ORDER;
    if (dimension->step > 0) {
      *sign = MI_NEGATIVE;
    }
    else {
      *sign = MI_POSITIVE;
    }
    break;
  case MI_POSITIVE:
    *sign = MI_POSITIVE;
    if (dimension->step > 0) {
      *file_order = MI_FILE_ORDER;
    }
    else {
      *file_order = MI_COUNTER_FILE_ORDER; 
    }
    break;  
  case MI_NEGATIVE:
    *sign = MI_NEGATIVE;
    if (dimension->step > 0) {
      *file_order = MI_COUNTER_FILE_ORDER;
    }
    else {
      *file_order = MI_FILE_ORDER; 
    }
    break;  
  default:
    return (MI_ERROR);
  }
  return (MI_NOERROR);
}

/*! Set the apparent order of voxels.
 */

int 
miset_dimension_apparent_voxel_order(midimhandle_t dimension, miflipping_t flipping_order)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  switch (flipping_order) {
  case MI_FILE_ORDER:
    dimension->flipping_order  = MI_FILE_ORDER;
    break;
  case MI_COUNTER_FILE_ORDER:
    dimension->flipping_order  = MI_COUNTER_FILE_ORDER;
    break;
  case MI_POSITIVE:
    dimension->flipping_order  = MI_POSITIVE;
    break;
    /*
    if (dimension->separation > 0) {
      dimension->flipping_order  = MI_FILE_ORDER;
    }
    else {
      dimension->flipping_order  = MI_COUNTER_FILE_ORDER;
    }
    break;
    */
  case MI_NEGATIVE:
    dimension->flipping_order  = MI_NEGATIVE;
    break;
    /*
    if (dimension->separation > 0) {
      dimension->flipping_order  = MI_COUNTER_FILE_ORDER;
    }
    else {
      dimension->flipping_order  = MI_FILE_ORDER;
    }
    break;
    */
  default:
    return (MI_ERROR);
  }
  
  return (MI_NOERROR);
}

/*! Get the class of a MINC dimension.
 */

int 
miget_dimension_class(midimhandle_t dimension, midimclass_t *class)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }

  switch (dimension->class) {
  case MI_DIMCLASS_ANY:
    *class = MI_DIMCLASS_ANY;
    break;
  case MI_DIMCLASS_SPATIAL:
    *class = MI_DIMCLASS_SPATIAL;
    break;
  case MI_DIMCLASS_TIME:
    *class = MI_DIMCLASS_TIME;
    break;
  case MI_DIMCLASS_SFREQUENCY:
    *class = MI_DIMCLASS_SFREQUENCY;
    break;
  case MI_DIMCLASS_TFREQUENCY:
    *class = MI_DIMCLASS_TFREQUENCY;
    break;
  case MI_DIMCLASS_USER:
    *class = MI_DIMCLASS_USER;
    break;
  case MI_DIMCLASS_RECORD:
    *class = MI_DIMCLASS_RECORD;
    break;
  default:
    return (MI_ERROR);
  }
  
  return (MI_NOERROR);
}

/*! Set the class of a MINC dimension.
 */

int 
miset_dimension_class(midimhandle_t dimension, midimclass_t class)
{
   if (dimension == NULL) {
    return (MI_ERROR);
  }
  switch (class) {
  case MI_DIMCLASS_ANY:
    dimension->class = MI_DIMCLASS_ANY;
    break;
  case MI_DIMCLASS_SPATIAL:
    dimension->class = MI_DIMCLASS_SPATIAL;
    break;
  case MI_DIMCLASS_TIME:
    dimension->class = MI_DIMCLASS_TIME;
    break;
  case MI_DIMCLASS_SFREQUENCY:
    dimension->class = MI_DIMCLASS_SFREQUENCY;
    break;
  case MI_DIMCLASS_TFREQUENCY:
    dimension->class = MI_DIMCLASS_TFREQUENCY;
    break;
  case MI_DIMCLASS_USER:
    dimension->class = MI_DIMCLASS_USER;
    break;
  case MI_DIMCLASS_RECORD:
    dimension->class = MI_DIMCLASS_RECORD;
    break;
  default:
    return (MI_ERROR);
  } 
  
  return (MI_NOERROR);
}

/*! Get the direction cosine vector of a given SPATIAL dimension.
 */

int 
miget_dimension_cosines(midimhandle_t dimension, double direction_cosines[3])
{
  if (dimension == NULL || (dimension->class != MI_DIMCLASS_SPATIAL &&
                            dimension->class != MI_DIMCLASS_SFREQUENCY)){
    return (MI_ERROR);
  }
  
  direction_cosines[0] = dimension->direction_cosines[0];
  direction_cosines[1] = dimension->direction_cosines[1];
  direction_cosines[2] = dimension->direction_cosines[2];

  return (MI_NOERROR);
}

/*! Set the direction cosine vector for a given SPATIAL dimension.
 */

int 
miset_dimension_cosines(midimhandle_t dimension, const double direction_cosines[3])
{
  
  if (dimension == NULL || dimension->class != MI_DIMCLASS_SPATIAL) {
    return (MI_ERROR);
  }
  
  dimension->direction_cosines[0] = direction_cosines[0];
  dimension->direction_cosines[1] = direction_cosines[1];
  dimension->direction_cosines[2] = direction_cosines[2];

  return (MI_NOERROR);
}

/*! Get the comments attribute for a given dimension.
 */

int
miget_dimension_description(midimhandle_t dimension, char **comments_ptr)
{

  if (dimension == NULL) {
    return (MI_ERROR);
  }
 
  *comments_ptr = strdup(dimension->comments);
  
  return (MI_NOERROR); 
}

/*! Set the comments attribute for a given dimension.
 */

int
miset_dimension_description(midimhandle_t dimension, const char *comments)
{

 if (dimension == NULL || comments == NULL) {
    return (MI_ERROR);
  }
 
  if ((strlen(comments) + 1) <= MI2_CHAR_LENGTH) {
    dimension->comments = strdup(comments);
  }
  else {
    return (MI_ERROR);
  }
    
  return (MI_NOERROR); 
}


/*! Get the identifier (name) of a MINC dimension.
 */

int 
miget_dimension_name(midimhandle_t dimension, char **name_ptr)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }

  *name_ptr = strdup(dimension->name);

  return (MI_NOERROR);
}

/*! Set the identifier (name) of a given MINC dimension.
 */

int 
miset_dimension_name(midimhandle_t dimension, const char *name)
{
  if (dimension == NULL || name == NULL) {
    return (MI_ERROR);
  }
 
  if ((strlen(name) + 1) <= MI2_CHAR_LENGTH) {
    dimension->name = strdup(name);
  }
  else {
    return (MI_ERROR);
  }
    
  return (MI_NOERROR);
}

/*! Get the absolute world coordinates of points along a MINC dimension.
 */

int 
miget_dimension_offsets(midimhandle_t dimension, unsigned long array_length, 
			unsigned long start_position, double offsets[])
{
  unsigned long  diff;
  int i, j=0;

  if (dimension == NULL || start_position > dimension->length ) {
    return (MI_ERROR);
  }
  if ((start_position + array_length) > dimension->length) {
    diff = dimension->length;
  }
  else {
    diff = array_length;
  }
  /* Allocate enough space for offsets.
   */
  offsets = (double *) malloc(diff*sizeof(double));
  
  if (dimension->offsets == NULL) {
    for (i=start_position; i <= diff ; i++) {
      /* For regularly sampled dimensions, the step value
	 is added to each value to get the next value.
       */
      offsets[j] = dimension->start + (i * dimension->step);
      j++;
    }
  }
  else {
    for (i=start_position; i <= diff ; i++) {
      offsets[j] = dimension->offsets[i];
      j++;
    }
  }
  return (MI_NOERROR);
}

/*! Set the absolute world coordinates of points along a MINC dimension.
 */

int 
miset_dimension_offsets(midimhandle_t dimension, unsigned long array_length, 
			unsigned long start_position, const double offsets[])
{
  unsigned long  diff;
  int i, j=0;
  /* Check to see whether the dimension is regularly sampled.
   */
  if (dimension == NULL || 
      (dimension->attr & MI_DIMATTR_NOT_REGULARLY_SAMPLED) == 0 || 
      start_position > dimension->length ) {
    return (MI_ERROR);
  }
  if ((start_position + array_length) > dimension->length) {
    diff = dimension->length;
  }
  else {
    diff = array_length;
  }
  
  /* Allocate space for the offsets if not already done.
   */
  if (dimension->offsets == NULL) {
    dimension->offsets = (double *) malloc(dimension->length*sizeof(double));
  }
  if (start_position == 0) {
    diff--;
  }
  for (i=start_position; i <= diff ; i++) {
      dimension->offsets[i] = offsets[j] ;
      j++;
    }
  return (MI_NOERROR);
}

/*! Get the sampling flag for a MINC dimension. 
 */

int 
miget_dimension_sampling_flag(midimhandle_t dimension, BOOLEAN *sampling_flag)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }

  *sampling_flag = (dimension->attr & MI_DIMATTR_NOT_REGULARLY_SAMPLED) != 0;

  return (MI_NOERROR);
}

/*! Set the sampling flag for a MINC dimension.
 */

int 
miset_dimension_sampling_flag(midimhandle_t dimension, BOOLEAN sampling_flag)
{
    if (dimension == NULL) {
        return (MI_ERROR);
    }
    if (sampling_flag) {
        dimension->attr |= MI_DIMATTR_NOT_REGULARLY_SAMPLED;
    }
    else {
        dimension->attr &= ~MI_DIMATTR_NOT_REGULARLY_SAMPLED;
    }
    return (MI_NOERROR);
}

/*! Get the sampling interval (STEP) for a single dimension.
 */

int 
miget_dimension_separation(midimhandle_t dimension, mivoxel_order_t voxel_order, 
			   double *separation_ptr)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  if (voxel_order == 0) {
    *separation_ptr = dimension->step;
  }
  else {
    *separation_ptr = -1 * dimension->step;
  }
  return (MI_NOERROR);
}

/*! Set the sampling interval (STEP) for a single dimension.
 */

int 
miset_dimension_separation(midimhandle_t dimension, double separation)
{
  /* file-order of voxels is assumed.
   */
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  
  dimension->step = separation;
  /* If not explicitly set, the width will be assumed to be equal to the
     dimension's step size.
  */
  //dimension->width = separation;

  return (MI_NOERROR);
}

/*! Get the sampling interval (STEP) for a list of dimensions.
 */

int 
miget_dimension_separations(const midimhandle_t dimensions[], mivoxel_order_t voxel_order,
			    int array_length, double separations[])
{
  int i;
  /* Allocated space for the separations array.
   */
  //separations  = (double *) malloc(array_length*sizeof(double));
  for (i=0; i< array_length; i++) {
    miget_dimension_separation(dimensions[i], voxel_order, &separations[i]);
  }
  
  return (MI_NOERROR);
}

/*! Set the sampling interval (STEP) for a list of dimensions.
 */

int 
miset_dimension_separations(const midimhandle_t dimensions[], int array_length, 
			    const double separations[])
{
  int i;
  for (i=0; i< array_length; i++) {
    miset_dimension_separation(dimensions[i],separations[i]);
  }
  return (MI_NOERROR);
}

/*! Get the length of a MINC dimension.
 */

int 
miget_dimension_size(midimhandle_t dimension, unsigned long *size_ptr)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  *size_ptr = dimension->length;
  return (MI_NOERROR);
}

/*! Set the length of a MINC dimension if not associated with a 
    volume.
 */

int 
miset_dimension_size(midimhandle_t dimension, unsigned long size)
{
  /* Check whether the dimension is associated with a volume.
   */
  if (dimension == NULL || dimension->volume_handle != NULL) {
    return (MI_ERROR);
  }
  dimension->length = size;
  return (MI_NOERROR);
}

/*! Retrieve the length of all dimensions in dimensions array.
 */

int 
miget_dimension_sizes(const midimhandle_t dimensions[], int array_length,
		      unsigned long sizes[])
{
  int i;
  /* Allocated space for the length array.
   */
  //sizes  = (unsigned long *) malloc(array_length*sizeof(unsigned long));
  for(i=0; i<array_length; i++) {
    miget_dimension_size(dimensions[i], &sizes[i]);
  }
    
  return (MI_NOERROR);
}

/*! Get the start value of a MINC dimension.
 */

int 
miget_dimension_start(midimhandle_t dimension, mivoxel_order_t voxel_order,
		      double *start_ptr)
{
  /* If voxel_order is set to apparent file order (i.e., 1)
     start = start + step * (n-1)
   */
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  if (voxel_order == 0) {
    *start_ptr = dimension->start;
  }
  else {
    
    *start_ptr = dimension->start + (dimension->step * (dimension->length-1));
  }
  return (MI_NOERROR);
}

/*! Set the origin of a MINC dimension.
 */

int 
miset_dimension_start(midimhandle_t dimension, double start_ptr)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  dimension->start = start_ptr;

  return (MI_NOERROR);
}

/*! Get the start values for MINC dimensions in dimensions array.
 */

int 
miget_dimension_starts(const midimhandle_t dimensions[], mivoxel_order_t voxel_order,
		       int array_length, double starts[])
{ 
  int i;
  /* Allocated space for the starts array.
   */
  //starts  = (double *) malloc(array_length*sizeof(double));
  for (i=0; i < array_length; i++) {
    miget_dimension_start(dimensions[i], voxel_order, &starts[i]);
  }

  return (MI_NOERROR);
}

/*! Set the start values for MINC dimensions in dimensions array.
 */

int 
miset_dimension_starts(const midimhandle_t dimensions[], int array_length, 
		       const double starts[])
{
  int i;
 
  for (i=0; i<array_length; i++) {
    miset_dimension_start(dimensions[i], starts[i]);
  }
  return (MI_NOERROR);
}

/*! Get the unit string for a MINC dimension.
 */

int 
miget_dimension_units(midimhandle_t dimension, char **units_ptr)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  
  *units_ptr = strdup(dimension->units);
  
  return (MI_NOERROR);
}

/*! Set the unit string for a MINC dimension.
 */

int 
miset_dimension_units(midimhandle_t dimension, const char *units)
{
  if (dimension == NULL) {
    return (MI_ERROR);
  }
  
  if (strlen(units) + 1 <= MI2_CHAR_LENGTH) {
    dimension->units = strdup(units);
  }
  else {
    return (MI_ERROR);
  }

  return (MI_NOERROR);
}

/*! Get A single full-width half-maximum value from a 
    regularly sampled dimension.
 */

int 
miget_dimension_width(midimhandle_t dimension, double *width_ptr)
{
  
  if (dimension == NULL || 
      (dimension->attr & MI_DIMATTR_NOT_REGULARLY_SAMPLED) != 0) {
    return (MI_ERROR);
  }
  *width_ptr = dimension->width;
  return (MI_NOERROR);
}

/*! Set the A single full-width half-maximum value for a 
    regulalry sampled dimension.
 */

int 
miset_dimension_width(midimhandle_t dimension, double width_ptr)
{
  if (dimension == NULL || 
      (dimension->attr & MI_DIMATTR_NOT_REGULARLY_SAMPLED) != 0) {
    return (MI_ERROR);
  }
  /* Check to make sure width value is positive.
   */
  if (width_ptr < 0) {
    dimension->width = -1 * width_ptr;
  }
  else {
    dimension->width = width_ptr;
  }
  return (MI_NOERROR);
}

/*! Get the full-width half-maximum value for points along an
    irregularly sampled dimension.
 */

int 
miget_dimension_widths(midimhandle_t dimension, mivoxel_order_t voxel_order,
		       unsigned long array_length, unsigned long start_position,
		       double widths[])
{
  unsigned long  diff;
  int i, j = 0;

  if (dimension == NULL || start_position > dimension->length) {
    return (MI_ERROR);
  }
  
  if ((start_position + array_length) > dimension->length) {
    diff = dimension->length;
  }
  else {
    diff = array_length;
  }
  /* Allocate space for the widths array
   */
  widths = (double *) malloc(diff*sizeof(double));
  /* Check to see whether the dimension is regularly sampled.
   */
  if (start_position == 0) {
    diff--;
  }
  if (dimension->widths == NULL) {
    for (i=start_position; i <= diff; i++) {
      widths[j] = dimension->width;
      j++;
    }
  }
  else { 
    /* If the apparent order is requested, the widths are returned
       REVERSE (flip) order.
     */
    if (voxel_order == 0) {
      for (i=start_position; i <= diff; i++) {
	widths[j] = dimension->widths[i];
	j++;
      }
    }
    else {
      for (i=diff; i >= start_position; i--) {
	widths[j] = dimension->widths[i];
	j++;
      }
    }
      
  }

  return (MI_NOERROR);
}

/*! Set the full-width half-maximum value for points along an
    irregularly sampled dimension.
 */

int 
miset_dimension_widths(midimhandle_t dimension, unsigned long array_length,
		       unsigned long start_position, const double widths[])
{
  unsigned long  diff;
  int i, j=0;
  /* Check to see whether the dimension is regularly sampled.
   */
  if (dimension == NULL || 
      (dimension->attr & MI_DIMATTR_NOT_REGULARLY_SAMPLED) == 0 || 
      start_position > dimension->length) {
    return (MI_ERROR);
  }

  if ((start_position + array_length) > dimension->length) {
    diff = dimension->length;
  }
  else {
    diff = array_length;
  }
  /* Allocate space for widths array if not already done
   */
  if (dimension->widths == NULL) {
    dimension->widths = (double *) malloc(dimension->length*sizeof(double));
  }
  if (start_position == 0) {
    diff--;
  }
  for (i=start_position; i <= diff; i++) {
    if (widths[i] < 0) {
      dimension->widths[i] = -1 * widths[j];
    }
    else {
      dimension->widths[i] = widths[j];
    }
    j++;
  }
  return (MI_NOERROR);
}


#ifdef M2_TEST
#define TESTRPT(msg, val) (error_cnt++, fprintf(stderr, \
                                  "Error reported on line #%d, %s: %d\n", \
                                  __LINE__, msg, val))

static int error_cnt = 0;

#define CX 10
#define CY 10
#define CZ 6
#define NDIMS 3

int main(int argc, char **argv)
{
  mihandle_t vol;
  int r;
  midimhandle_t dim[3];
  mivolumeprops_t props;
  double cosines[3];
  double offsets[3];
  double widths[3];
  int n;
  midimhandle_t dimens[3];
  unsigned long coords[NDIMS];
    unsigned long count[NDIMS];
    int i,j,k;
    struct test {
        int r;
        int g;
        int b;
    } voxel;
    int result = 1;
  /* Write data one voxel at a time. */
    for (i = 0; i < NDIMS; i++) {
        count[i] = 1;
    }

    r = minew_volume_props(&props);
    r = miset_props_compression_type(props, MI_COMPRESS_ZLIB);
    r = miset_props_zlib_compression(props, 3);
     r = miset_props_multi_resolution(props, 1, 3);
  if (r < 0) {
    TESTRPT("failed", r);
  }
  
  r = micreate_dimension("xspace",MI_DIMCLASS_SPATIAL,MI_DIMATTR_REGULARLY_SAMPLED, 10,&dim[0]);
  if (r < 0) {
    TESTRPT("failed", r);
  }
  //dim[0]=dimh;
  
  r = micreate_dimension("yspace",MI_DIMCLASS_SPATIAL,MI_DIMATTR_REGULARLY_SAMPLED, 10,&dim[1]);
  if (r < 0) {
    TESTRPT("failed", r);
  }
  //dim[1]=dimh1;
  r = micreate_dimension("zspace",MI_DIMCLASS_SPATIAL,MI_DIMATTR_REGULARLY_SAMPLED, 6,&dim[2]);
  if (r < 0) {
    TESTRPT("failed", r);
  }
  
  //dim[2]=dimh2;
 
  r = micreate_volume("test_multi_h5.mnc", 3, dim, MI_TYPE_UINT, MI_CLASS_REAL,props,&vol);
  if (r < 0) {
    TESTRPT("failed", r);
  }

  r = micreate_volume_image(vol);
  if (r < 0) {
    TESTRPT("failed", r);
  }
  
  r = miget_volume_dimension_count(vol, MI_DIMCLASS_SPATIAL, MI_DIMATTR_ALL, &n);
  if (r < 0) {
    TESTRPT("failed", r);
  }
  printf( " N is %d \n", n);

  for (i = 0; i < CX; i++) {
        for (j = 0; j < CY; j++) {
            for (k = 0; k < CZ; k++) {
                coords[0] = i;
                coords[1] = j;
                coords[2] = k;

                voxel.r = i;
                voxel.g = j;
                voxel.b = k;
                
                result = miset_voxel_value_hyperslab(vol, MI_TYPE_UINT,
						     coords, count, &voxel);
                if (result < 0) {
                    TESTRPT("Error writing voxel", result);
                }
            }
        }
    }

 
  /* call miselect_resolution() 
   */
  r = miselect_resolution(vol,1);
  //r = miflush_from_resolution(vol, 3);
  if (r < 0) {
    TESTRPT("failed", r);
  }
  r = miclose_volume(vol);
  if (r < 0) {
    TESTRPT("failed", r);
  }
  
  if (error_cnt != 0) {
    fprintf(stderr, "%d error%s reported\n", 
	    error_cnt, (error_cnt == 1) ? "" : "s");
  }
  else {
    fprintf(stderr, "No errors\n");
   
  }
  return (error_cnt);
}
#endif