changeset 1635:46f087c96c53

Latest rounds of changes
author bert <bert>
date Mon, 26 Jan 2004 23:25:46 +0000
parents b5ba3b68710b
children ea0e0249daeb
files libsrc2/Makefile libsrc2/convert.c libsrc2/hyper.c libsrc2/m2util.c libsrc2/minc2.h libsrc2/minc2_private.h libsrc2/record.c libsrc2/slice.c libsrc2/valid.c libsrc2/volprops.c libsrc2/volume.c
diffstat 11 files changed, 393 insertions(+), 271 deletions(-) [+]
line wrap: on
line diff
--- a/libsrc2/Makefile
+++ b/libsrc2/Makefile
@@ -12,7 +12,8 @@
 	hyper.o \
 	label.o \
 	slice.o \
-	valid.o 
+	valid.o \
+	record.o
 
 LIBS = -lminc -lnetcdf -lhdf5 -lm
 
@@ -27,7 +28,8 @@
 	hyper-test \
 	slice-test \
 	valid-test \
-	convert-test
+	convert-test \
+	record-test
 
 libminc2.a: $(OBJS)
 	ar r libminc2.a $(OBJS)
@@ -157,6 +159,17 @@
 valid.o: valid.c minc2.h minc2_private.h
 	gcc $(CPPFLAGS) -Wall -g -c -o valid.o valid.c
 
+record-test-objs = record-test.o libminc2.a
+
+record-test: $(record-test-objs)
+	gcc $(LDFLAGS) -Wall -g -o record-test $(record-test-objs) $(LIBS)
+
+record-test.o: record.c minc2.h minc2_private.h
+	gcc -DM2_TEST $(CPPFLAGS) -Wall -g -c -o record-test.o record.c
+
+record.o: record.c minc2.h minc2_private.h
+	gcc $(CPPFLAGS) -Wall -g -c -o record.o record.c
+
 volume.o: volume.c minc2.h minc2_private.h
 	gcc $(CPPFLAGS) -Wall -g -c -o volume.o volume.c
 
--- a/libsrc2/convert.c
+++ b/libsrc2/convert.c
@@ -48,7 +48,7 @@
     real_range = slice_max - slice_min;
     
     real_value = (real_value - real_offset) / real_range;
-    *voxel_value_ptr = (real_value + voxel_offset) * voxel_range;
+    *voxel_value_ptr = (real_value * voxel_range) + voxel_offset;
 
     return (result);
 }
@@ -88,7 +88,7 @@
     real_range = slice_max - slice_min;
     
     voxel_value = (voxel_value - voxel_offset) / voxel_range;
-    *real_value_ptr = (voxel_value + real_offset) * real_range;
+    *real_value_ptr = (voxel_value * real_range) + real_offset;
     return (result);
 }
 
@@ -161,16 +161,15 @@
                  int ndims,
                  double *value_ptr)
 {
+    double voxel;
     int result;
-    unsigned long count[ndims]; /*  */
-    int i;
 
-    for (i = 0; i < ndims; i++) {
-        count[i] = 1;
+    result = miget_voxel_value(volume, coords, ndims, &voxel);
+    if (result != MI_NOERROR) {
+        return (result);
     }
-    result = miget_real_value_hyperslab(volume, MI_TYPE_DOUBLE,
-                                        coords, count, value_ptr);
-    return (result);
+    miconvert_voxel_to_real(volume, coords, ndims, voxel, value_ptr);
+    return (MI_NOERROR);
 }
 
 /** This function sets the  real value of a position in the MINC
@@ -183,16 +182,10 @@
                  int ndims,
                  double value)
 {
-    int result;
-    unsigned long count[ndims]; /*  */
-    int i;
+    double voxel;
 
-    for (i = 0; i < ndims; i++) {
-        count[i] = 1;
-    }
-    result = miset_real_value_hyperslab(volume, MI_TYPE_DOUBLE,
-                                        coords, count, &value);
-    return (result);
+    miconvert_real_to_voxel(volume, coords, ndims, value, &voxel);
+    return (miset_voxel_value(volume, coords, ndims, voxel));
 }
 
 
@@ -237,14 +230,13 @@
                   double *voxel_ptr)
 {
     int result;
-    unsigned long count[MAX_VAR_DIMS];
+    long count[MI2_MAX_VAR_DIMS];
     int i;
 
-    for (i = 0; i < ndims; i++) {
+    for (i = 0; i < volume->number_of_dims; i++) {
         count[i] = 1;
     }
-    
-    result = miget_voxel_value_hyperslab(volume, MI_TYPE_DOUBLE, 
+    result = miset_voxel_value_hyperslab(volume, MI_TYPE_DOUBLE, 
                                          coords, count, voxel_ptr);
     return (result);
 }
@@ -260,7 +252,7 @@
                   double voxel)
 {
     int result;
-    unsigned long count[MAX_VAR_DIMS];
+    unsigned long count[MI2_MAX_VAR_DIMS];
     int i;
 
     for (i = 0; i < ndims; i++) {
--- a/libsrc2/hyper.c
+++ b/libsrc2/hyper.c
@@ -80,9 +80,9 @@
                   const int *map,
                   const int *dir)
 {
-    long index[MAX_VAR_DIMS];
-    long index_perm[MAX_VAR_DIMS];
-    long lengths_perm[MAX_VAR_DIMS];
+    long index[MI2_MAX_VAR_DIMS];
+    long index_perm[MI2_MAX_VAR_DIMS];
+    long lengths_perm[MI2_MAX_VAR_DIMS];
     unsigned char *temp;
     mioffset_t offset_start;
     mioffset_t offset_next;
@@ -260,6 +260,78 @@
     return (MI_NOERROR);
 }
 
+/** "semiprivate" function for translating coordinates.
+ */
+int
+mitranslate_hyperslab_origin(mihandle_t volume,
+                             const long start[],
+                             const long count[],
+                             hsize_t hdf_start[],
+                             hsize_t hdf_count[],
+                             int dir[])
+{
+    int n_different = 0;
+    int file_i;
+    int ndims = volume->number_of_dims;
+
+    for (file_i = 0; file_i < ndims; file_i++) {
+        midimhandle_t hdim;
+        int user_i;
+
+        /* Set up the basic translations of dimensions, for
+         * flipping directions and swapping indices.
+         */
+        if (volume->dim_indices != NULL) {
+            /* Have to swap indices */
+            user_i = volume->dim_indices[file_i];  
+            if (user_i != file_i) {
+                n_different++;
+            }
+        }
+        else {
+            user_i = file_i;
+        }
+
+        hdim = volume->dim_handles[file_i];
+
+        switch (hdim->flipping_order) {
+        case MI_FILE_ORDER:
+            hdf_start[file_i] = start[user_i];
+            dir[file_i] = 1;
+            break;
+
+        case MI_COUNTER_FILE_ORDER:
+            hdf_start[file_i] = hdim->length - start[user_i] - count[user_i];
+            dir[file_i] = -1;
+            break;
+            
+        case MI_POSITIVE:
+            if (hdim->step > 0) { /* Positive? */
+                hdf_start[file_i] = start[user_i]; /* Use raw file order. */
+                dir[file_i] = 1;
+            }
+            else {
+                hdf_start[file_i] = hdim->length - start[user_i] - count[user_i];
+                dir[file_i] = -1;
+            }
+            break;
+
+        case MI_NEGATIVE:
+            if (hdim->step < 0) { /* Negative? */
+                hdf_start[file_i] = start[user_i]; /* Use raw file order */
+                dir[file_i] = 1;
+            }
+            else {
+                hdf_start[file_i] = hdim->length - start[user_i] - count[user_i];
+                dir[file_i] = -1;
+            }
+            break;
+        }
+        hdf_count[file_i] = count[user_i];
+    }
+    return (n_different);
+}
+
 /** Read/write a hyperslab of data.  This is the simplified function
  * which performs no value conversion.  It is much more efficient than
  * mirw_hyperslab_icv()
@@ -277,13 +349,12 @@
     hid_t dset_id = -1;
     hid_t mspc_id = -1;
     hid_t fspc_id = -1;
-    char path[128];
+    char path[MI2_MAX_PATH];
     int result = MI_ERROR;
-    hsize_t hdf_start[MAX_VAR_DIMS];
-    hsize_t hdf_count[MAX_VAR_DIMS];
-    int dir[MAX_VAR_DIMS];
+    hsize_t hdf_start[MI2_MAX_VAR_DIMS];
+    hsize_t hdf_count[MI2_MAX_VAR_DIMS];
+    int dir[MI2_MAX_VAR_DIMS];
     int ndims;
-    int file_i;
     int n_different = 0;
 
     file_id = volume->hdf_id;
@@ -311,61 +382,13 @@
         mspc_id = H5Screate(H5S_SCALAR);
     }
     else {
-        for (file_i = 0; file_i < ndims; file_i++) {
-            midimhandle_t hdim;
-            int user_i;
-
-            /* Set up the basic translations of dimensions, for
-             * flipping directions and swapping indices.
-             */
-            if (volume->dim_indices != NULL) {
-                /* Have to swap indices */
-                user_i = volume->dim_indices[file_i];  
-                if (user_i != file_i) {
-                    n_different++;
-                }
-            }
-            else {
-                user_i = file_i;
-            }
-
-            hdim = volume->dim_handles[file_i];
-
-            switch (hdim->flipping_order) {
-            case MI_FILE_ORDER:
-                hdf_start[file_i] = start[user_i];
-                dir[file_i] = 1;
-                break;
+        n_different = mitranslate_hyperslab_origin(volume, 
+                                                   start,
+                                                   count,
+                                                   hdf_start,
+                                                   hdf_count,
+                                                   dir);
 
-            case MI_COUNTER_FILE_ORDER:
-                hdf_start[file_i] = hdim->length - start[user_i] - count[user_i];
-                dir[file_i] = -1;
-                break;
-
-            case MI_POSITIVE:
-                if (hdim->step > 0) { /* Positive? */
-                    hdf_start[file_i] = start[user_i]; /* Use raw file order. */
-                    dir[file_i] = 1;
-                }
-                else {
-                    hdf_start[file_i] = hdim->length - start[user_i] - count[user_i];
-                    dir[file_i] = -1;
-                }
-                break;
-
-            case MI_NEGATIVE:
-                if (hdim->step < 0) { /* Negative? */
-                    hdf_start[file_i] = start[user_i]; /* Use raw file order */
-                    dir[file_i] = 1;
-                }
-                else {
-                    hdf_start[file_i] = hdim->length - start[user_i] - count[user_i];
-                    dir[file_i] = -1;
-                }
-                break;
-            }
-            hdf_count[file_i] = count[user_i];
-        }
         mspc_id = H5Screate_simple(ndims, hdf_count, NULL);
         if (mspc_id < 0) {
             goto cleanup;
@@ -434,10 +457,9 @@
     int nc_type;
     int file_id;
     int result = MI_ERROR;
-    long icv_start[MAX_VAR_DIMS];
-    long icv_count[MAX_VAR_DIMS];
-    int dir[MAX_VAR_DIMS];      /* Direction, either +1 or -1 */
-    int file_i;
+    long icv_start[MI2_MAX_VAR_DIMS];
+    long icv_count[MI2_MAX_VAR_DIMS];
+    int dir[MI2_MAX_VAR_DIMS];  /* Direction, either +1 or -1 */
     int n_different = 0;
 
     miicv_inqint(icv, MI_ICV_TYPE, &nc_type);
@@ -449,81 +471,19 @@
     ndims = volume->number_of_dims;
 
     if (ndims != 0) {
-        for (file_i = 0; file_i < ndims; file_i++) {
-            midimhandle_t hdim;
-            int user_i;
-
-            /* Set up the basic translations of dimensions, for
-             * flipping directions and swapping indices.
-             */
-            if (volume->dim_indices != NULL) {
-                /* Have to swap indices */
-                user_i = volume->dim_indices[file_i];  
-                if (user_i != file_i) {
-                    n_different++;
-                }
-            }
-            else {
-                user_i = file_i;
-            }
-
-            hdim = volume->dim_handles[file_i];
-
-            switch (hdim->flipping_order) {
-            case MI_FILE_ORDER:
-                /* 
-                 * Always use raw file order.
-                 */
-                icv_start[file_i] = start[user_i];
-                dir[file_i] = 1;
-                break;
-
-            case MI_COUNTER_FILE_ORDER:
-                /* 
-                 * Always use reverse file order.
-                 */
-                icv_start[file_i] = hdim->length - start[user_i] - count[user_i];
-                dir[file_i] = -1;
-                n_different++;
-                break;
+        int i;
+        hsize_t hdf_start[MI2_MAX_VAR_DIMS];
+        hsize_t hdf_count[MI2_MAX_VAR_DIMS];
 
-            case MI_POSITIVE:
-                if (hdim->step > 0) { /* Positive? */
-                    /* 
-                     * Use raw file order.
-                     */
-                    icv_start[file_i] = start[user_i];
-                    dir[file_i] = 1;
-                }
-                else {
-                    /*
-                     * Use reverse file order.
-                     */
-                    icv_start[file_i] = hdim->length - start[user_i] - count[user_i];
-                    dir[file_i] = -1;
-                    n_different++;
-                }
-                break;
-
-            case MI_NEGATIVE:
-                if (hdim->step < 0) { /* Negative? */
-                    /*
-                     * Use raw file order.
-                     */
-                    icv_start[file_i] = start[user_i]; /* Use raw file order */
-                    dir[file_i] = 1;
-                }
-                else {
-                    /*
-                     * Use reverse file order.
-                     */
-                    icv_start[file_i] = hdim->length - start[user_i] - count[user_i];
-                    dir[file_i] = -1;
-                    n_different++;
-                }
-                break;
-            }
-            icv_count[file_i] = count[user_i];
+        n_different = mitranslate_hyperslab_origin(volume, 
+                                                   start,
+                                                   count,
+                                                   hdf_start,
+                                                   hdf_count,
+                                                   dir);
+        for (i = 0; i < ndims; i++) {
+            icv_start[i] = hdf_start[i];
+            icv_count[i] = hdf_count[i];
         }
     }
 
--- a/libsrc2/m2util.c
+++ b/libsrc2/m2util.c
@@ -1,5 +1,7 @@
-/************************************************************************
- * MINC 2.0 PRIVATE UTILITY FUNCTIONS
+/** \file m2util.c
+ * \brief MINC 2.0 Private utility functions
+ * \author Leila Baghdadi, Bert Vincent
+ *
  ************************************************************************/
 #include <stdlib.h>
 #include <math.h>
@@ -47,6 +49,26 @@
     case MI_TYPE_UINT:
 	type_id = H5Tcopy(H5T_NATIVE_UINT);
 	break;
+    case MI_TYPE_SCOMPLEX:
+        type_id = H5Tcreate(H5T_COMPOUND, 4);
+        H5Tinsert(type_id, "real", 0, H5T_NATIVE_SHORT);
+        H5Tinsert(type_id, "imag", 2, H5T_NATIVE_SHORT);
+        break;
+    case MI_TYPE_ICOMPLEX:
+        type_id = H5Tcreate(H5T_COMPOUND, 8);
+        H5Tinsert(type_id, "real", 0, H5T_NATIVE_INT);
+        H5Tinsert(type_id, "imag", 4, H5T_NATIVE_INT);
+        break;
+    case MI_TYPE_FCOMPLEX:
+        type_id = H5Tcreate(H5T_COMPOUND, 8);
+        H5Tinsert(type_id, "real", 0, H5T_NATIVE_FLOAT);
+        H5Tinsert(type_id, "imag", 4, H5T_NATIVE_FLOAT);
+        break;
+    case MI_TYPE_DCOMPLEX:
+        type_id = H5Tcreate(H5T_COMPOUND, 16);
+        H5Tinsert(type_id, "real", 0, H5T_NATIVE_DOUBLE);
+        H5Tinsert(type_id, "imag", 8, H5T_NATIVE_DOUBLE);
+        break;
     default:
         type_id = H5Tcopy(mitype); /* Else it is a standard HDF type handle */
 	break;
@@ -134,7 +156,7 @@
 miget_voxel_count(int mincid)
 {
     int imgid;
-    int dim[MAX_VAR_DIMS];
+    int dim[MI2_MAX_VAR_DIMS];
     int idim;
     int ndims;
     mi_i64_t nvoxels;
@@ -276,7 +298,9 @@
 	return (MI_ERROR);
     }
     
-    hdf_attr = H5Aopen_name(hdf_loc, name);
+    H5E_BEGIN_TRY {
+        hdf_attr = H5Aopen_name(hdf_loc, name);
+    } H5E_END_TRY;
     if (hdf_attr < 0) {
 	return (MI_ERROR);
     }
@@ -342,7 +366,7 @@
 void
 mifind_spatial_dims(int mincid, int space_to_dim[], int dim_to_space[])
 {
-    int imgid, dim[MAX_VAR_DIMS];
+    int imgid, dim[MI2_MAX_VAR_DIMS];
     int idim, ndims, world_index;
     char dimname[MAX_NC_NAME];
 
@@ -350,7 +374,7 @@
     for (idim = 0; idim < 3; idim++)
         space_to_dim[idim] = -1;
     
-    for (idim = 0; idim < MAX_VAR_DIMS; idim++)
+    for (idim = 0; idim < MI2_MAX_VAR_DIMS; idim++)
         dim_to_space[idim] = -1;
 
     /* Get the dimension ids for the image variable 
@@ -839,7 +863,7 @@
 int
 minc_create_thumbnail(hid_t file_id, int grp)
 {
-    char path[MAX_PATH];
+    char path[MI2_MAX_PATH];
     hid_t grp_id;
 
     /* Don't handle negative or overly large numbers!
@@ -907,10 +931,10 @@
 int
 minc_update_thumbnail(hid_t loc_id, int igrp, int ogrp)
 {
-    hsize_t isize[MAX_VAR_DIMS];
-    hsize_t osize[MAX_VAR_DIMS];
-    hsize_t count[MAX_VAR_DIMS];
-    hsize_t start[MAX_VAR_DIMS];
+    hsize_t isize[MI2_MAX_VAR_DIMS];
+    hsize_t osize[MI2_MAX_VAR_DIMS];
+    hsize_t count[MI2_MAX_VAR_DIMS];
+    hsize_t start[MI2_MAX_VAR_DIMS];
     hid_t idst_id;              /* Input dataset */
     hid_t odst_id;              /* Output dataset */
     hid_t ifspc_id;             /* Input "file" dataspace */
@@ -918,7 +942,7 @@
     hid_t typ_id;               /* Type ID */
     hid_t imspc_id;
     hid_t omspc_id;
-    char path[MAX_PATH];
+    char path[MI2_MAX_PATH];
     int ndims;
     int scale;
     int i;
@@ -1251,3 +1275,28 @@
     }
     return ( result );
 }
+
+/** Function to read a scalar variable.
+ */
+miget_scalar(hid_t loc_id, hid_t type_id, const char *path, void *data)
+{
+    hid_t dset_id;
+    hid_t spc_id;
+    int result = MI_ERROR;
+
+    dset_id = H5Dopen(loc_id, path);
+    if (dset_id >= 0) {
+        spc_id = H5Dget_space(dset_id);
+        if (spc_id >= 0) {
+            if (H5Sget_simple_extent_ndims(spc_id) == 0) {
+                if (H5Dread(dset_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, 
+                            data) >= 0) {
+                    result = MI_NOERROR;
+                }
+            }
+            H5Sclose(spc_id);
+        }
+        H5Dclose(dset_id);
+    }
+    return (result);
+}
--- a/libsrc2/minc2.h
+++ b/libsrc2/minc2.h
@@ -27,13 +27,19 @@
 #define MI_DIMATTR_REGULARLY_SAMPLED 0x1
 #define MI_DIMATTR_NOT_REGULARLY_SAMPLED 0x2
 
+/** Maximum length of a standard string.
+ */
 #define MI2_CHAR_LENGTH 128
 
-#define MI2_MAX_BLOCK_EDGES 3   /* Don't do 4D or greater chunks for now */
+/** Maximum number of dimensions a variable can have.
+ */
+#define MI2_MAX_VAR_DIMS 100
+
 #define MI2_CHUNK_SIZE 32	/* Length of chunk, per dimension */
+#define MI2_DEFAULT_ZLIB_LEVEL 4
 #define MAX_ZLIB_LEVEL 9
 
-#define MAX_PATH 32
+#define MI2_MAX_PATH 128
 #define MAX_RESOLUTION_GROUP 16
 #define MAX_CD_ELEMENTS 100
 
--- a/libsrc2/minc2_private.h
+++ b/libsrc2/minc2_private.h
@@ -99,7 +99,9 @@
   int selected_resolution;      /* The current resolution (0-N) */
   int mode;                     /* Open mode */
   hid_t type_id;                /* Type ID if record or label type. */
-  hid_t plist_id;             /* Image property list */
+  hid_t plist_id;               /* Image property list */
+  double scale_min;             /* Global minimum */
+  double scale_max;             /* Global maximum */
 };
 
 extern hid_t midescend_path(hid_t file_id, const char *path);
@@ -125,3 +127,12 @@
 
 extern void miinit(void);
 extern void miinit_enum(hid_t);
+
+extern int mitranslate_hyperslab_origin(mihandle_t volume, 
+                                        const long start[], 
+                                        const long count[],
+                                        hsize_t hdf_start[],
+                                        hsize_t hdf_count[],
+                                        int dir[]);
+extern int miget_scalar(hid_t loc_id, hid_t type_id, const char *path, 
+                        void *data);
--- a/libsrc2/record.c
+++ b/libsrc2/record.c
@@ -137,6 +137,7 @@
 
     micreate_volume_image(hvol);
 
+
     miclose_volume(hvol);
 
     if (error_cnt != 0) {
--- a/libsrc2/slice.c
+++ b/libsrc2/slice.c
@@ -51,7 +51,7 @@
     }
 
     if (!volume->has_slice_scaling) {
-        mirw_volume_minmax(opcode, volume, value);
+        return mirw_volume_minmax(opcode, volume, value);
     }
 
     file_id = volume->hdf_id;
@@ -263,7 +263,16 @@
     if (volume->has_slice_scaling) {
 	return (MI_ERROR);
     }
-
+    if ((opcode & MIRW_SCALE_SET) == 0) {
+        if (opcode & MIRW_SCALE_MIN) {
+            *value = volume->scale_min;
+            return (MI_NOERROR);
+        }
+        else {
+            *value = volume->scale_max;
+            return (MI_NOERROR);
+        }
+    }
     file_id = volume->hdf_id;
     if (opcode & MIRW_SCALE_MIN) {
 	sprintf(path, "/minc-2.0/image/%d/image-min", 
@@ -306,6 +315,15 @@
 	return (MI_ERROR);
     }
 
+    /* Update the "cached" values.
+     */
+    if (opcode & MIRW_SCALE_MIN) {
+        volume->scale_min = *value;
+    }
+    else {
+        volume->scale_max = *value;
+    }
+
     H5Sclose(fspc_id);
     H5Sclose(mspc_id);
     H5Dclose(dset_id);
@@ -398,7 +416,7 @@
 	return (MI_ERROR);
     }
 
-    r = mirw_volume_minmax(MIRW_SCALE_MIN + MIRW_SCALE_MIN, volume, &vol_min);
+    r = mirw_volume_minmax(MIRW_SCALE_MIN + MIRW_SCALE_SET, volume, &vol_min);
     if (r < 0) {
 	return (MI_ERROR);
     }
--- a/libsrc2/valid.c
+++ b/libsrc2/valid.c
@@ -47,6 +47,7 @@
      * to valid_min?
      */
     volume->valid_max = valid_max;
+    misave_valid_range(volume);
     return (MI_NOERROR);
 }
 
@@ -79,6 +80,7 @@
         return (MI_ERROR);       /* Invalid arguments */
     }
     volume->valid_min = valid_min;
+    misave_valid_range(volume);
     return (MI_NOERROR);
 }
 
@@ -119,6 +121,7 @@
      */
     volume->valid_min = valid_min;
     volume->valid_max = valid_max;
+    misave_valid_range(volume);
     return (MI_NOERROR);
 }
 
--- a/libsrc2/volprops.c
+++ b/libsrc2/volprops.c
@@ -1,5 +1,17 @@
-/************************************************************************
- * MINC 2.0 "VOLUME_PROPERTIES" FUNCTIONS
+/** \file volprops.c
+ * \brief MINC 2.0 Volume properties functions
+ * \author Leila Baghdadi
+ * 
+ * These functions manipulate "volume properties" objects, which are
+ * used to control several options related to MINC 2.0 volume structure.
+ * These include compression, blocking, multi-resolution, and record s
+ * structure.
+ *
+ * This approach was adopted with the intent that it would make the 
+ * default volume creation as simple as possible, while allowing a
+ * lot of control for more advanced applications.  This approach to 
+ * managing properties is also believed to be more readily extensible than 
+ * any obvious alternative.
  ************************************************************************/
 #include <stdlib.h>
 #include <hdf5.h>
@@ -25,7 +37,7 @@
   handle->depth = 0;
   handle->compression_type = MI_COMPRESS_NONE;
   handle->zlib_level = 0;
-  handle->edge_count = 1;
+  handle->edge_count = 0;
   handle->edge_lengths = NULL;
   handle->max_lengths = 0;
   handle->record_length = 0;
@@ -88,10 +100,10 @@
   /* Get the layout of the raw data for a dataset.
    */
   if (H5Pget_layout(hdf_plist) == H5D_CHUNKED) {
-      hsize_t dims[MI2_MAX_BLOCK_EDGES];
+      hsize_t dims[MI2_MAX_VAR_DIMS];
       int i;
       /* Returns chunk dimensionality */
-      handle->edge_count = H5Pget_chunk(hdf_plist, MI2_MAX_BLOCK_EDGES, dims);
+      handle->edge_count = H5Pget_chunk(hdf_plist, MI2_MAX_VAR_DIMS, dims);
       if (handle->edge_count < 0) {
 	return (MI_ERROR);
       }
@@ -240,9 +252,9 @@
 int
 miset_props_compression_type(mivolumeprops_t props, micompression_t compression_type)
 {
- 
-  int edge_lengths[MI2_MAX_BLOCK_EDGES] = {MI2_CHUNK_SIZE, MI2_CHUNK_SIZE, MI2_CHUNK_SIZE};
- 
+    int i;
+    int edge_lengths[MI2_MAX_VAR_DIMS];
+
  if (props == NULL) {
     return (MI_ERROR);
   }
@@ -252,7 +264,11 @@
    break;
  case MI_COMPRESS_ZLIB:
    props->compression_type = MI_COMPRESS_ZLIB;
-   miset_props_blocking(props, MI2_MAX_BLOCK_EDGES, edge_lengths);
+   props->zlib_level = MI2_DEFAULT_ZLIB_LEVEL;
+   for (i = 0; i < MI2_MAX_VAR_DIMS; i++) {
+       edge_lengths[i] = MI2_CHUNK_SIZE;
+   }
+   miset_props_blocking(props, MI2_MAX_VAR_DIMS, edge_lengths);
    break;
  default:
    return (MI_ERROR);
@@ -307,7 +323,7 @@
 {
   int i;
   
-  if (props == NULL || edge_count > MI2_MAX_BLOCK_EDGES) {
+  if (props == NULL || edge_count > MI2_MAX_VAR_DIMS) {
     return (MI_ERROR);
   }
   
@@ -412,7 +428,7 @@
   BOOLEAN enable_flag;
   int zlib_level;
   int depth;
-  int edge_lengths[MI2_MAX_BLOCK_EDGES];
+  int edge_lengths[MI2_MAX_VAR_DIMS];
   int edge_count;
   int i;
  /* Turn off automatic error reporting - we'll take care of this
@@ -480,7 +496,7 @@
 	  TESTRPT("failed", r);
       }
       r = miget_props_blocking(props, &edge_count, edge_lengths, 
-			       MI2_MAX_BLOCK_EDGES);
+			       MI2_MAX_VAR_DIMS);
       if (r < 0) {
 	  TESTRPT("failed", r);
       }
--- a/libsrc2/volume.c
+++ b/libsrc2/volume.c
@@ -9,6 +9,7 @@
 #include <hdf5.h>
 #include <limits.h>
 #include <float.h>
+#include <math.h>
 #include "minc2.h"
 #include "minc2_private.h"
 
@@ -19,20 +20,18 @@
 static void miread_valid_range(mihandle_t volume, double *valid_max, 
                                double *valid_min);
 
-static void misave_valid_range(mihandle_t volume, double valid_max, 
-                               double valid_min);
+void misave_valid_range(mihandle_t volume);
 
 /**
  */
 int
 micreate_volume_image(mihandle_t volume)
 {
-    char dimorder[128];
+    char dimorder[MI2_CHAR_LENGTH];
     int i;
     hid_t dataspace_id;
-    hid_t dimage_id;
-    hsize_t hdf_size[100];
-    hid_t grp_id;
+    hid_t dset_id;
+    hsize_t hdf_size[MI2_MAX_VAR_DIMS];
 
     /* Try creating IMAGE dataset i.e. /minc-2.0/image/0/image
      */
@@ -46,7 +45,9 @@
            list of dimension names.
         */
         strcat(dimorder, volume->dim_handles[i]->name);
-        strcat(dimorder, ",");
+        if (i != volume->number_of_dims - 1) {
+            strcat(dimorder, ",");
+        }
     }
 
     /* Create a SIMPLE dataspace  */
@@ -54,24 +55,69 @@
     if (dataspace_id < 0) {
         return (MI_ERROR);
     }
-#if 0
-    grp_id = midescend_path(volume->hdf_id, "/minc-2.0/image/0");
-    if (grp_id < 0) {
+    dset_id = H5Dcreate(volume->hdf_id, "/minc-2.0/image/0/image", 
+                        volume->type_id, 
+                        dataspace_id, volume->plist_id);
+    if (dset_id < 0) {  
         return (MI_ERROR);
     }
-#endif
-    dimage_id = H5Dcreate(volume->hdf_id, "/minc-2.0/image/0/image", volume->type_id, 
-                          dataspace_id, volume->plist_id);
-    if (dimage_id < 0) {  
-        return (MI_ERROR);
-    }
+    hdf_var_declare(volume->hdf_id, "image", "/minc-2.0/image/0/image",
+                    volume->number_of_dims, hdf_size);
     /* Create the dimorder attribute, ordered comma-separated
        list of dimension names.
     */
-    miset_attr_at_loc(dimage_id, "dimorder", MI_TYPE_STRING,
+    miset_attr_at_loc(dset_id, "dimorder", MI_TYPE_STRING,
                       strlen(dimorder), dimorder);
-    H5Dclose(dimage_id);
+
+    H5Dclose(dset_id);
     H5Sclose(dataspace_id);
+
+    if (volume->volume_class == MI_CLASS_REAL) {
+        int ndims;
+        if (volume->has_slice_scaling) {
+            /* TODO: Find the slowest-varying spatial dimension; that forms
+             * the basis for the image-min and image-max variables.  Right
+             * now this is an oversimplification!
+             */
+            ndims = volume->number_of_dims - 2;
+            dataspace_id = H5Screate_simple(ndims, hdf_size, NULL);
+        }
+        else {
+            ndims = 0;
+            dataspace_id = H5Screate(H5S_SCALAR);
+        }
+
+        if (ndims != 0) {
+            dimorder[0] = '\0'; /* Set string to empty */
+            for (i = 0; i < ndims; i++) {
+                /* Create the dimorder string, ordered comma-separated
+                   list of dimension names.
+                */
+                strcat(dimorder, volume->dim_handles[i]->name);
+                if (i != volume->number_of_dims - 1) {
+                    strcat(dimorder, ",");
+                }
+            }
+        }
+
+        dset_id = H5Dcreate(volume->hdf_id, "/minc-2.0/image/0/image-min",
+                            H5T_NATIVE_DOUBLE, dataspace_id, H5P_DEFAULT);
+        if (ndims != 0) {
+            miset_attr_at_loc(dset_id, "dimorder", MI_TYPE_STRING,
+                              strlen(dimorder), dimorder);
+        }
+        H5Dclose(dset_id);
+        hdf_var_declare(volume->hdf_id, "image-min", "/minc-2.0/image/0/image-min", ndims, hdf_size);
+        dset_id = H5Dcreate(volume->hdf_id, "/minc-2.0/image/0/image-max",
+                            H5T_NATIVE_DOUBLE, dataspace_id, H5P_DEFAULT);
+        if (ndims != 0) {
+            miset_attr_at_loc(dset_id, "dimorder", MI_TYPE_STRING,
+                              strlen(dimorder), dimorder);
+        }
+        hdf_var_declare(volume->hdf_id, "image-max", "/minc-2.0/image/0/image-max", ndims, hdf_size);
+        H5Dclose(dset_id);
+        H5Sclose(dataspace_id);
+    }
     return (MI_NOERROR);
 }
 
@@ -90,15 +136,14 @@
   hid_t hdf_plist;
   hid_t fspc_id;
   hsize_t dim[1];
-  hid_t grp_root_id, grp_image_id;
-  hid_t grp_fullimage_id, grp_dimensions_id; 
+  hid_t grp_dimensions_id; 
   herr_t status;
   hid_t dataset_id = -1;
   hid_t dataset_width = -1;
   hid_t dataspace_id = -1;
   char *name;
   int size;
-  hsize_t hdf_size[100];        /* TODO: define this */
+  hsize_t hdf_size[MI2_MAX_VAR_DIMS];
   volumehandle *handle;
   volprops *props_handle;
   unsigned int v;
@@ -110,6 +155,8 @@
     return (MI_ERROR);
   }    
 
+  /* Allocate space for the volume handle
+   */
   handle = (volumehandle *)malloc(sizeof(*handle));
   if (handle == NULL) {
     return (MI_ERROR);
@@ -118,7 +165,8 @@
   /* convert minc type to hdf type
    */
   hdf_type = mitype_to_hdftype(volume_type);
-  if (volume_class == MI_CLASS_LABEL) {
+  switch (volume_class) {
+  case MI_CLASS_LABEL:
       /* A volume of class LABEL must have an integer type.
        */
       switch (volume_type) {
@@ -139,13 +187,27 @@
       default:
           return (MI_ERROR);
       }
-  }
-  else if (volume_class == MI_CLASS_COMPLEX) {
-  }
-  else if (volume_class == MI_CLASS_UNIFORM_RECORD) {
-  }
-  else {
+      break;
+
+  case MI_CLASS_COMPLEX:
+      switch (volume_type) {
+      case MI_TYPE_SCOMPLEX:
+      case MI_TYPE_ICOMPLEX:
+      case MI_TYPE_FCOMPLEX:
+      case MI_TYPE_DCOMPLEX:
+          handle->type_id = hdf_type;
+          break;
+      default:
+          return (MI_ERROR);
+      }
+      break;
+  case MI_CLASS_UNIFORM_RECORD:
+      handle->type_id = H5Tcreate(H5T_COMPOUND, H5Tget_size(hdf_type));
+      H5Tclose(hdf_type);
+      break;
+  default:
       handle->type_id = hdf_type;
+      break;
   }
 
   /* Create file in HDF5 with the given filename and
@@ -153,32 +215,11 @@
                    erasing all data previously stored in the file.
      and create ID and ID access as default.
   */
-  file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
+  file_id = hdf_create(filename, H5F_ACC_TRUNC);
   if (file_id < 0) {
     return (MI_ERROR);
   }
   
-  /* Create the root group.
-   */
-  grp_root_id = H5Gcreate(file_id, MI_ROOT_PATH, 0);
-  if (grp_root_id < 0) {
-      return (MI_ERROR);
-  }
-
-  /* Create the image group.
-   */
-  grp_image_id = H5Gcreate(grp_root_id, MI_IMAGE_PATH, 0);
-  if (grp_image_id < 0) {
-      return (MI_ERROR);
-  }
-
-  /* Create the "full image" group "/minc-2.0/image/0"
-   */
-  grp_fullimage_id = H5Gcreate(grp_image_id, MI_FULLIMAGE_PATH, 0);
-  if (grp_fullimage_id < 0) {
-      return (MI_ERROR);
-  }
-
   hdf_plist = H5Pcreate(H5P_DATASET_CREATE);
   if (hdf_plist < 0) {
     return (MI_ERROR);
@@ -187,15 +228,17 @@
   handle->plist_id = hdf_plist;
 
   /* Set fill value to guarantee valid data on incomplete datasets.
-   * TODO: figure out what to set this to for complex/record types.
    */
-  v = 0;
-  H5Pset_fill_value(hdf_plist, H5T_NATIVE_UINT, &v);
+  {
+      char *tmp = calloc(1, H5Tget_size(handle->type_id));
+      H5Pset_fill_value(hdf_plist, handle->type_id, tmp);
+      free(tmp);
+  }
 
   /* See if chunking and/or compression should be enabled */
   if (create_props != NULL &&
       (create_props->compression_type == MI_COMPRESS_ZLIB ||
-       create_props->edge_count == number_of_dimensions)) {
+       create_props->edge_count != 0)) {
       stat = H5Pset_layout(hdf_plist, H5D_CHUNKED); /* Chunked data */
       if (stat < 0) {
           return (MI_ERROR);
@@ -206,7 +249,7 @@
       }
     
       /* Sets the size of the chunks used to store a chunked layout dataset */
-      stat = H5Pset_chunk(hdf_plist, create_props->edge_count, hdf_size);
+      stat = H5Pset_chunk(hdf_plist, number_of_dimensions, hdf_size);
       if (stat < 0) {
           return (MI_ERROR);
       }
@@ -225,7 +268,7 @@
 
    /* Try creating DIMENSIONS GROUP i.e. /minc-2.0/dimensions
     */
-  grp_dimensions_id = H5Gcreate(grp_root_id, MI_FULLDIMENSIONS_PATH , 0);
+  grp_dimensions_id = H5Gopen(file_id, "/minc-2.0/dimensions");
   if (grp_dimensions_id < 0) {
       return (MI_ERROR);
   }
@@ -260,16 +303,15 @@
     
     if (dimensions[i]->attr & MI_DIMATTR_NOT_REGULARLY_SAMPLED) {
       if (dimensions[i]->offsets == NULL) {
-	printf(" OFFSETS MUST BE SPECIFIED FOR IRREGULARLY SAMPLED DIMENSIONS \n");
 	return (MI_ERROR);
       }
       else {
-	
 	fspc_id = H5Dget_space(dataset_id);
 	if (fspc_id < 0) {
 	  return (MI_ERROR);
 	}
-	status = H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, dataspace_id, fspc_id, H5P_DEFAULT, dimensions[i]->offsets);
+	status = H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, dataspace_id, 
+                          fspc_id, H5P_DEFAULT, dimensions[i]->offsets);
 	if (status < 0) {
 	  return (MI_ERROR);
 	}
@@ -286,6 +328,8 @@
 	if (status < 0) {
 	  return (MI_ERROR);
 	}
+        miset_attr_at_loc(dataset_width, "length", MI_TYPE_INT,
+                          1, &dimensions[i]->length);
 	H5Dclose(dataset_width);
         free(name);
       }
@@ -307,38 +351,39 @@
     miset_attr_at_loc(dataset_id, "direction_cosines", MI_TYPE_DOUBLE,
                       3, dimensions[i]->direction_cosines);
 
+    /* Save dimension length */
     miset_attr_at_loc(dataset_id, "length", MI_TYPE_INT,
                       1, &dimensions[i]->length);
 
+    /* Save step value. */
     miset_attr_at_loc(dataset_id, "step", MI_TYPE_DOUBLE,
                       1, &dimensions[i]->step);
 
+    /* Save start value. */
     miset_attr_at_loc(dataset_id, "start", MI_TYPE_DOUBLE,
                       1, &dimensions[i]->start);
    
-
+    /* Save units. */
     miset_attr_at_loc(dataset_id, "units", MI_TYPE_STRING,
                       strlen(dimensions[i]->units), dimensions[i]->units);
 
+    /* Save sample width. */
     miset_attr_at_loc(dataset_id, "width", MI_TYPE_DOUBLE,
                       1,  &dimensions[i]->width);
 
+    /* Save comments. */
     miset_attr_at_loc(dataset_id, "comments", MI_TYPE_STRING,
                       strlen(dimensions[i]->comments), dimensions[i]->comments);
+    H5Dclose(dataset_id);
   }
   
-  H5Dclose(dataset_id);
   H5Gclose(grp_dimensions_id);
-  H5Gclose(grp_fullimage_id);
-  H5Gclose(grp_image_id);
-  H5Gclose(grp_root_id);
   
-
-  /* Allocate space for the volume handle
-   */
   handle->hdf_id = file_id;
   handle->mode = MI2_OPEN_RDWR;
   handle->has_slice_scaling = FALSE;
+  handle->scale_min = -1.0;
+  handle->scale_max = 1.0;
   handle->number_of_dims = number_of_dimensions;
   handle->dim_handles = (midimhandle_t *)malloc(number_of_dimensions*sizeof(int));
   if (handle->dim_handles == NULL) {
@@ -524,8 +569,8 @@
 _miget_file_dimension(mihandle_t volume, const char *dimname, 
                       midimhandle_t *hdim_ptr)
 {
-    char path[128];
-    char temp[128];
+    char path[MI2_CHAR_LENGTH];
+    char temp[MI2_CHAR_LENGTH];
     midimhandle_t hdim;
 
     sprintf(path, "/minc-2.0/dimensions/%s", dimname);
@@ -598,9 +643,10 @@
     hid_t space_id;
     volumehandle *handle;
     int hdf_mode;
-    char dimorder[128];
+    char dimorder[MI2_CHAR_LENGTH];
     int i,r;
     char *p1, *p2;
+
     miinit();
 
     if (mode == MI2_OPEN_READ) {
@@ -669,6 +715,14 @@
 	}
 	H5Dclose(dset_id);	/* Close the dataset handle */
     }
+
+    if (!handle->has_slice_scaling) {
+        miget_scalar(handle->hdf_id, H5T_NATIVE_DOUBLE,
+                     "/minc-2.0/image/0/image-min", &handle->scale_min);
+
+        miget_scalar(handle->hdf_id, H5T_NATIVE_DOUBLE,
+                     "/minc-2.0/image/0/image-max", &handle->scale_max);
+    }
     
     /* Read the current settings for valid-range */
     miread_valid_range(handle, &handle->valid_max, &handle->valid_min);
@@ -691,7 +745,7 @@
 int
 miflush_volume(mihandle_t volume)
 {
-    misave_valid_range(volume, volume->valid_max, volume->valid_min);
+    misave_valid_range(volume);
     return (MI_NOERROR);
 }
 
@@ -800,13 +854,12 @@
     }
 }
 
-static void
-misave_valid_range(mihandle_t volume, double valid_max, double valid_min)
+void
+misave_valid_range(mihandle_t volume)
 {
     double range[2];
-    range[0] = valid_min;
-    range[1] = valid_max;
-
+    range[0] = volume->valid_min;
+    range[1] = volume->valid_max;
     miset_attribute(volume, "/minc-2.0/image/0/image", "valid_range",
                     MI_TYPE_DOUBLE, 2, range);
 }