changeset 2552:345f8c960657

added ezminc library
author Vladimir S. FONOV <vladimir.fonov@gmail.com>
date Thu, 08 Dec 2011 18:47:56 -0500
parents 3fe122bac48b
children 0b52afea4248
files CMakeLists.txt ezminc/CMakeLists.txt ezminc/minc_1_rw.cpp ezminc/minc_1_rw.h ezminc/minc_1_simple.h ezminc/minc_1_simple_rw.cpp ezminc/minc_1_simple_rw.h ezminc/minc_io_4d_volume.h ezminc/minc_io_exceptions.h ezminc/minc_io_fixed_vector.h ezminc/minc_io_simple_volume.h
diffstat 11 files changed, 3677 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,6 +31,7 @@
 OPTION(BUILD_MINC2      "Support minc2 file format" ON)
 OPTION(BUILD_TOOLS      "Build minc tools (mincreshape,mincresample, etc)" ON)
 OPTION(BUILD_CONVERTERS "Build minc conversion programs (mnc2nii, nii2mnc , dcm2mnc...)" ON)
+OPTION(BUILD_EZMINC     "Build C++ interface library EZminc" ON)
 
 ADD_DEFINITIONS(-DHAVE_CONFIG_H)
 
@@ -237,3 +238,7 @@
 # and then the conversion subdir
 ADD_SUBDIRECTORY( conversion )
 ENDIF(BUILD_CONVERTERS)
+
+IF(BUILD_EZMINC)
+ADD_SUBDIRECTORY( ezminc )
+ENDIF(BUILD_EZMINC)
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/ezminc/CMakeLists.txt
@@ -0,0 +1,39 @@
+LINK_LIBRARIES(
+    m 
+    z )
+
+IF(USE_MINC2)
+  ADD_DEFINITIONS( -DMINC2 )
+  LINK_LIBRARIES(volume_io2 minc2 netcdf hdf5 z)
+ELSE(USE_MINC2)
+  LINK_LIBRARIES(volume_io minc netcdf)
+ENDIF(USE_MINC2)
+
+
+INCLUDE_DIRECTORIES( 
+  ${VOLUME_TOOLS_BINARY_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+
+SET( MINC_IO_HEADERS 
+    minc_io_exceptions.h 
+    minc_io_fixed_vector.h  
+    minc_io_simple_volume.h
+    minc_1_rw.h
+    minc_1_simple.h
+    minc_1_simple_rw.h
+    minc_io_4d_volume.h
+   )
+   
+SET( MINC_IO_SRC 
+    minc_1_rw.cpp
+    minc_1_simple_rw.cpp
+  )
+
+ADD_LIBRARY( minc_io ${MINC_IO_HEADERS} ${MINC_IO_SRC})
+
+
+INSTALL(TARGETS minc_io ARCHIVE DESTINATION lib)
+INSTALL(FILES  ${MINC_IO_HEADERS} DESTINATION include)
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_1_rw.cpp
@@ -0,0 +1,1421 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : 
+@DESCRIPTION: Primitive" interface to minc files, using minctoraw and rawtominc programs
+              does not require linking with minc2 library.
+              Created during the days when minc2 didn't compile on 64bit architecture
+@COPYRIGHT  :
+              Copyright 2007 Vladimir Fonov, 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.
+---------------------------------------------------------------------------- */
+#include <stdio.h>
+#include <iostream>
+#include <sstream>
+#include <string.h>
+//minc stuff
+#include <math.h>
+#include <limits.h>
+#include "minc_1_rw.h"
+
+namespace minc
+{
+  dim_info::dim_info(int l, double sta,
+                     double spa,dimensions d,
+                     bool hd):
+      length(l),start(sta),step(spa),dim(d),have_dir_cos(hd)
+  {
+    switch(dim)
+    {
+      case dim_info::DIM_X:name=MIxspace;break;
+      case dim_info::DIM_Y:name=MIyspace;break;
+      case dim_info::DIM_Z:name=MIzspace;break;
+      case dim_info::DIM_TIME:name=MItime;break;
+      case dim_info::DIM_VEC:name=MIvector_dimension;break;
+      default: REPORT_ERROR("Unknown Dimension!");
+    }
+  }
+  
+  minc_1_base::minc_1_base():
+    _dims(3,0),
+    _map_to_std(5,-1),
+    _mincid(MI_ERROR),
+    _imgid(MI_ERROR),
+    _icvid(MI_ERROR),
+    _cur(MAX_VAR_DIMS,0),
+    _slab(MAX_VAR_DIMS,1),
+    _last(false),
+    _datatype(MI_ORIGINAL_TYPE),
+    _io_datatype(MI_ORIGINAL_TYPE),
+    _slab_len(0),
+    _positive_directions(true),
+    _minc2(false)
+  {
+    _icvid=miicv_create();
+  }
+
+  //! destructor, closes minc file
+  minc_1_base::~minc_1_base()
+  {
+    close();
+  }
+  
+  void minc_1_base::close(void)
+  {
+    if(_icvid!=MI_ERROR)
+    {
+      miicv_free(_icvid);
+      _icvid=MI_ERROR;
+    }
+    if(_mincid!=MI_ERROR) miclose(_mincid);
+    _mincid=MI_ERROR;
+  }
+  
+  
+  std::string minc_1_base::history(void) const
+  {
+    nc_type datatype;
+    int att_length;
+#ifndef WIN32
+    int op=ncopts;
+#endif //WIN32
+    //ncopts=0;
+    if ((ncattinq(_mincid, NC_GLOBAL, MIhistory, &datatype,&att_length) == MI_ERROR) ||
+        (datatype != NC_CHAR))
+    {
+      //ncopts=op;
+      return "";
+    }
+    char* str = new char[att_length+1];
+    str[0] = '\0';
+    miattgetstr(_mincid, NC_GLOBAL, (char*)MIhistory, att_length,str);
+    //ncopts=op;
+    std::string r(str);
+    delete [] str;
+    return r;
+  }
+  
+  //code from mincinfo
+  int minc_1_base::var_number(void) const
+  {
+    int nvars;
+    if(ncinquire(_mincid, NULL, &nvars, NULL, NULL)!=MI_ERROR)
+      return nvars;
+    return 0;
+  }
+  
+  std::string minc_1_base::var_name(int no) const
+  {
+    char name[MAX_NC_NAME];
+    if(ncvarinq(_mincid, no, name, NULL, NULL, NULL, NULL)!=MI_ERROR)
+      return name;
+  }
+  
+  int minc_1_base::att_number(const char *var_name) const
+  {
+    int varid;
+    int natts;
+    if (*var_name=='\0') {
+        varid = NC_GLOBAL;
+    } else {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return 0;
+    }
+    return att_number(varid);
+  }
+  
+  int minc_1_base::var_id(const char *var_name) const
+  {
+    return ncvarid(_mincid, var_name);
+  }
+
+  long minc_1_base::var_length(const char *var_name) const
+  {
+    int varid=var_id(var_name);
+    if(varid!=MI_ERROR)
+      return var_length(varid);
+    else
+      return 0;
+  }
+    
+  long minc_1_base::var_length(int var_id) const
+  {
+    int vardims;
+    
+    if(ncvarinq(_mincid, var_id, NULL, NULL, &vardims, NULL, NULL)!=MI_ERROR)
+    {
+      if(vardims==0) return 1;
+      int *dims=new int[vardims];
+      if(ncvarinq(_mincid, var_id, NULL, NULL, NULL, dims, NULL)!=MI_ERROR)
+      {
+        long varlength=1;
+        if(ncdiminq(_mincid,dims[0],NULL,&varlength)!=MI_ERROR)
+        {
+          delete[] dims;
+          return varlength;
+        }
+        delete[] dims;
+        return 1;
+      } else {
+        delete[] dims;
+        return 1;
+      }
+    }
+    return 0;
+  }
+
+  
+  //! get the number of attributes associated with variable
+  int minc_1_base::att_number(int var_no) const
+  {
+    int natts;
+    if(ncvarinq(_mincid, var_no, NULL, NULL, NULL, NULL, &natts)!=MI_ERROR)
+      return natts;
+    return 0;
+  }
+  
+  
+  std::string minc_1_base::att_name(const char *var_name,int no) const
+  {
+    int varid;
+    int attid;
+    char name[MAX_NC_NAME];
+    if (*var_name=='\0') 
+        varid = NC_GLOBAL;
+    else 
+    {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return "";
+    }
+    return att_name(varid,no);
+  }
+  
+  std::string minc_1_base::att_name(int varid,int no) const
+  {
+    int attid;
+    char name[MAX_NC_NAME];
+    if(ncattname(_mincid, varid, no, name)==MI_ERROR)
+      return "";
+    
+    return name;
+  }
+  
+  std::string minc_1_base::att_value_string(const char *var_name,const char *att_name) const
+  {
+    int varid;
+    int attid;
+    char name[MAX_NC_NAME];
+    if (*var_name=='\0') 
+        varid = NC_GLOBAL;
+    else 
+    {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return "";
+    }
+    return att_value_string(varid,att_name);
+  }
+  
+  std::string minc_1_base::att_value_string(int varid,const char *att_name) const
+  {
+    int att_length;
+    nc_type datatype;
+    
+    //TODO: make this handle other (double?) data types correctly
+    if ((ncattinq(_mincid, varid, (char *)att_name, &datatype,&att_length) == MI_ERROR) ||
+        (datatype != NC_CHAR))
+    {
+      //ncopts=op;
+      return "";
+    }
+    char* str = new char[att_length+1];
+    str[0] = '\0';
+    miattgetstr(_mincid, varid, (char *)att_name, att_length, str);
+    //ncopts=op;
+    std::string r(str);
+    delete [] str;
+    return r;
+  }
+  
+  std::vector<double> minc_1_base::att_value_double(const char *var_name,const char *att_name) const
+  {
+    int varid;
+    if (*var_name=='\0') 
+        varid = NC_GLOBAL;
+    else 
+    {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return std::vector<double>(0);
+    }
+    return att_value_double(varid,att_name);
+  }
+  
+  std::vector<short> minc_1_base::att_value_short(const char *var_name,const char *att_name) const
+  {
+    int varid;
+    if (*var_name=='\0') 
+      varid = NC_GLOBAL;
+    else 
+    {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return std::vector<short>(0);
+    }
+    return att_value_short(varid,att_name);
+  }
+  
+  std::vector<unsigned char> minc_1_base::att_value_byte(const char *var_name,const char *att_name) const
+  {
+    int varid;
+    if (*var_name=='\0') 
+      varid = NC_GLOBAL;
+    else 
+    {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return std::vector<unsigned char>(0);
+    }
+    return att_value_byte(varid,att_name);    
+  }
+  
+  
+  std::vector<int> minc_1_base::att_value_int(const char *var_name,const char *att_name) const
+  {
+    int varid;
+    if (*var_name=='\0') 
+      varid = NC_GLOBAL;
+    else 
+    {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return std::vector<int>(0);
+    }
+    return att_value_int(varid,att_name);
+  }
+  
+  std::vector<int> minc_1_base::att_value_int(int varid,const char *att_name) const 
+  {
+    int att_length;
+    nc_type datatype;
+    
+    if ((ncattinq(_mincid, varid, (char *)att_name, &datatype,&att_length) == MI_ERROR) ||
+         (datatype != NC_INT))
+    {
+      //ncopts=op;
+      return std::vector<int>(0);
+    }
+    std::vector<int> r(att_length);
+    miattget(_mincid, varid, (char*)att_name, NC_INT, att_length,&r[0], NULL) ;
+    //ncopts=op;
+    return r;
+  }
+
+  
+  std::vector<double> minc_1_base::att_value_double(int varid,const char *att_name) const
+  {
+    int att_length;
+    nc_type datatype;
+    
+    //TODO: make this handle other (double?) data types correctly
+    if ((ncattinq(_mincid, varid, (char *)att_name, &datatype,&att_length) == MI_ERROR) ||
+        (datatype != NC_DOUBLE))
+    {
+      //ncopts=op;
+      return std::vector<double>(0);
+    }
+    std::vector<double> r(att_length);
+    miattget(_mincid, varid, (char*)att_name, NC_DOUBLE, att_length,&r[0], NULL) ;
+    //ncopts=op;
+    return r;
+  }
+  
+  std::vector<short> minc_1_base::att_value_short(int varid,const char *att_name) const
+  {
+    int att_length;
+    nc_type datatype;
+    
+    //TODO: make this handle other (double?) data types correctly
+    if ((ncattinq(_mincid, varid, (char *)att_name, &datatype,&att_length) == MI_ERROR) ||
+         (datatype != NC_SHORT))
+    {
+      //ncopts=op;
+      return std::vector<short>(0);
+    }
+    std::vector<short> r(att_length);
+    miattget(_mincid, varid, (char*)att_name, NC_SHORT, att_length,&r[0], NULL) ;
+    //ncopts=op;
+    return r;
+  }
+  
+  std::vector<unsigned char> minc_1_base::att_value_byte(int varid,const char *att_name) const
+  {
+    int att_length;
+    nc_type datatype;
+    
+    //TODO: make this handle other (double?) data types correctly
+    if ((ncattinq(_mincid, varid, (char *)att_name, &datatype,&att_length) == MI_ERROR) ||
+         (datatype != NC_BYTE))
+    {
+      //ncopts=op;
+      return std::vector<unsigned char>(0);
+    }
+    std::vector<unsigned char> r(att_length);
+    miattget(_mincid, varid, (char*)att_name, NC_BYTE, att_length,&r[0], NULL) ;
+    //ncopts=op;
+    return r;
+  }
+  
+  
+  nc_type minc_1_base::att_type(const char *var_name,const char *att_name) const
+  {
+    int varid;
+    if (*var_name=='\0') 
+        varid = NC_GLOBAL;
+    else 
+    {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return MI_ORIGINAL_TYPE;
+    }
+    return att_type(varid,att_name);
+  }
+  
+  nc_type minc_1_base::att_type(int varid,const char *att_name) const
+  {
+    int att_length;
+    nc_type datatype;
+    
+    if(ncattinq(_mincid, varid, (char *)att_name, &datatype,&att_length) == MI_ERROR)
+      return MI_ORIGINAL_TYPE;
+    return datatype;
+  }
+  
+
+  int minc_1_base::att_length(const char *var_name,const char *att_name) const
+  {
+    int varid;
+    if (*var_name=='\0') 
+        varid = NC_GLOBAL;
+    else 
+    {
+      if((varid = ncvarid(_mincid, var_name))==MI_ERROR)
+        return 0;
+    }
+    return att_length(varid,att_name);
+  }
+  
+  int minc_1_base::att_length(int varid,const char *att_name) const
+  {
+    int att_length;
+    nc_type datatype;
+    
+    if(ncattinq(_mincid, varid, (char *)att_name, &datatype,&att_length) == MI_ERROR)
+      return 0;
+    
+    return att_length;
+  }
+  
+  
+  minc_1_reader::minc_1_reader(const minc_1_reader&):_metadate_only(false),_have_temp_file(false),_read_prepared(false)
+  {
+  }
+  
+  minc_1_reader::minc_1_reader():_metadate_only(false),_have_temp_file(false),_read_prepared(false)
+  {
+  }
+  
+  
+  //based on the code from mincextract
+  void minc_1_reader::open(const char *path,bool positive_directions/*=true*/,bool metadate_only/*=false*/,bool rw/*=false*/)
+  {
+#ifndef WIN32
+    ncopts = 0;
+#endif 
+    _metadate_only=metadate_only;
+    _read_prepared=false;
+    int element_size;
+    int idim;
+    int nstart, ncount;
+    _positive_directions=positive_directions;
+    //ncopts = 0;
+
+    // Open the file 
+
+    // Expand file 
+    if(_metadate_only)
+    { 
+      int created_tempfile;
+      char * tempfile = miexpand_file((char*)path, NULL, true, &created_tempfile);
+      if (tempfile == NULL) REPORT_ERROR("Error expanding minc file");
+      _tempfile=tempfile;
+      path=_tempfile.c_str();
+      _have_temp_file=created_tempfile;
+    }
+    _mincid = miopen((char*)path, rw?NC_WRITE:NC_NOWRITE);
+
+    if(_mincid == MI_ERROR) REPORT_ERROR("Can't open minc file for reading!");
+#ifdef MINC2
+   if (MI2_ISH5OBJ(_mincid)) {
+     _minc2 = true;
+   }
+#endif
+
+    /* Inquire about the image variable */
+    _imgid = ncvarid(_mincid, MIimage);
+    if(_imgid == MI_ERROR) REPORT_ERROR("Can't get Image ID");
+    ncvarinq(_mincid, _imgid, NULL, NULL, &_ndims, mdims, NULL);
+    //get image data type... not used for now
+    miget_datatype(_mincid, _imgid, &_datatype, &_is_signed);
+    //dir_cos.SetIdentity();
+    int dim_cnt=0;
+    miget_image_range(_mincid, _image_range);
+    //go through dimensions , calculating parameters for reshaping into ZYX array if needed
+    _info.resize(_ndims);
+    _world_matrix.resize(_ndims*4,0.0);
+    _voxel_matrix.resize(_ndims*4,0);
+    //_dir_cos.resize(_ndims*_ndims,0.0);
+    
+    for(int i=_ndims-1;i>=0;i--) 
+    {
+      //_world_matrix[i*(_ndims+1)]=1.0;
+      //_voxel_matrix[i*(_ndims+1)]=1.0;
+      char dimname[MAX_NC_NAME];
+      long dimlength;
+      //get dimensions info
+      ncdiminq(_mincid, mdims[i], dimname, &dimlength);
+      _info[i].name=dimname;
+      _info[i].length=dimlength;
+      _info[i].have_dir_cos=false;
+      int axis=-1;
+      unsigned int sz=0;
+      
+      if(!strcmp(dimname,MIxspace))
+      { 
+        _dims[0]=dimlength;axis=0;
+        _info[i].dim=dim_info::DIM_X;
+        _map_to_std[1]=i;
+      } else if(!strcmp(dimname,MIyspace)) { 
+        _dims[1]=dimlength;axis=1;
+        _info[i].dim=dim_info::DIM_Y;
+        _map_to_std[2]=i;
+      } else if(!strcmp(dimname,MIzspace)) { 
+        _dims[2]=dimlength;axis=2;
+        _info[i].dim=dim_info::DIM_Z;
+        _map_to_std[3]=i;
+      } else if(!strcmp(dimname,MIvector_dimension)) { 
+         axis=-1;
+        _info[i].dim=dim_info::DIM_VEC;
+        _map_to_std[0]=i;
+      } else if(!strcmp(dimname,MItime)) { 
+         axis=3;
+        _info[i].dim=dim_info::DIM_TIME;
+        _map_to_std[4]=i;
+      } else  {
+        REPORT_ERROR ("Unknown dimension");
+        _info[i].dim=dim_info::DIM_UNKNOWN;
+      }
+      
+      if(_info[i].dim!=dim_info::DIM_VEC)
+      {
+        //ncopts = 0;
+        int dimid = ncvarid(_mincid, dimname);
+        //ncopts = NC_VERBOSE | NC_FATAL;
+        if (dimid == MI_ERROR) continue;
+               
+        // Get dimension attributes
+        //ncopts = 0;
+        miattget1(_mincid, dimid, (char*)MIstep, NC_DOUBLE, &_info[i].step);
+        if(_info[i].step == 0.0)
+           _info[i].step = 1.0;
+        miattget1(_mincid, dimid, (char*)MIstart, NC_DOUBLE, &_info[i].start);
+          
+        if(_positive_directions && _info[i].step<0.0)
+        {
+          _info[i].start+=_info[i].step*(dimlength-1);
+          _info[i].step=-_info[i].step;
+        }
+        
+        if(miattget(_mincid, dimid, (char*)MIdirection_cosines, NC_DOUBLE, 3, &_info[i].dir_cos[0], NULL)!= MI_ERROR)
+        {
+          _info[i].have_dir_cos=true;
+          
+          /* Normalize the direction cosine */
+          double len=sqrt(_info[i].dir_cos[0]*_info[i].dir_cos[0]+
+                          _info[i].dir_cos[1]*_info[i].dir_cos[1]+
+                          _info[i].dir_cos[2]*_info[i].dir_cos[2]);
+          
+          if(len>1e-6 && fabs(len-1.0)>1e-6) //TODO: use some epsiolon here?
+          {
+            for(int a=0;a<3;a++)
+              _info[i].dir_cos[a]/=len;
+          }
+          
+        } 
+        // fill voxel matrix
+        _voxel_matrix[i*4+axis]=1;
+      } else { //vectors don't have spatial component!
+        _info[i].start=0;
+        _info[i].step=0.0;
+        _info[i].dir_cos[0]=_info[i].dir_cos[1]=_info[i].dir_cos[2]=0.0;
+        _info[i].have_dir_cos=false;
+      }
+      
+      //fill world matrix
+      for(int a=0;a<3;a++)
+        _world_matrix[i*4+a]=_info[i].dir_cos[a]*_info[i].step;
+      if(axis==3) //time
+        _world_matrix[i*4+3]=_info[i].step;
+      else
+        _world_matrix[i*4+3]=0.0;
+    }
+    //ncopts = NC_VERBOSE | NC_FATAL;
+    
+    // now let's find out the slice dimensions
+    int idmax = ncvarid(_mincid, MIimagemax);
+    _slice_dimensions=0;
+    if(idmax != MI_ERROR) 
+    {
+      int nmax_dims;
+      int mmax_dims[MAX_VAR_DIMS];
+      ncvarinq(_mincid, _imgid, NULL, NULL, &nmax_dims, mmax_dims, NULL);
+      if(nmax_dims>0)
+        _slice_dimensions=_ndims-nmax_dims;
+    } 
+    
+    if(_slice_dimensions<=0)
+    {
+      if(_info[_ndims-1].dim==dim_info::DIM_VEC || _info[_ndims-1].dim==dim_info::DIM_TIME) 
+        _slice_dimensions=std::min(_ndims,3);
+      else 
+        _slice_dimensions=std::min(_ndims,2);
+    }
+    std::fill(_slab.begin(),_slab.end(),1);
+    _slab_len=1;
+    for(int i=0;i<_slice_dimensions;i++)
+    {
+      _slab[_ndims-i-1]=_info[_ndims-i-1].length;
+      _slab_len*=_info[_ndims-i-1].length;
+    }
+  }
+  
+  minc_1_reader::~minc_1_reader()
+  {
+    if(_have_temp_file)
+      remove(_tempfile.c_str());
+  }
+
+  minc_1_writer::minc_1_writer():
+      _set_image_range(false),_set_slice_range(false),
+      _calc_min_max(true),_write_prepared(false)
+  {
+  }
+
+  minc_1_writer::minc_1_writer(const minc_1_writer&):
+      _set_image_range(false),_set_slice_range(false),
+      _calc_min_max(true),_write_prepared(false)
+  {
+  }
+  
+  
+  void minc_1_writer::open(const char *path,const minc_info& inf,int slice_dimensions,nc_type datatype,int _s)
+  {
+#ifndef WIN32
+    ncopts = 0;
+#endif
+	  _info=inf;
+    //int  mdims[MAX_VAR_DIMS];
+    double vrange[2];
+    _write_prepared=false;
+    
+    _mincid = micreate((char*)path, NC_CLOBBER/*|MI2_CREATE_V2*/); //TODO: add environment variable checking
+#ifdef MINC2
+    if (MI2_ISH5OBJ(_mincid)) { //micreate might create MINC2 file if environment variable is set
+      _minc2 = true;
+    }
+#endif
+    _ndims=_info.size();
+    _datatype=datatype;
+    _slice_dimensions=slice_dimensions;
+    _is_signed=_s;
+    fill(_map_to_std.begin(),_map_to_std.end(),-1);
+    for(int i=_ndims-1;i>=0;i--)
+    {
+      //just a precaution
+      switch(_info[i].dim)
+      {
+        case dim_info::DIM_X:_info[i].name=MIxspace;_map_to_std[1]=i;break;
+        case dim_info::DIM_Y:_info[i].name=MIyspace;_map_to_std[2]=i;break;
+        case dim_info::DIM_Z:_info[i].name=MIzspace;_map_to_std[3]=i;break;
+        case dim_info::DIM_TIME:_info[i].name=MItime;_map_to_std[4]=i;break;
+        default:
+        case dim_info::DIM_VEC:_info[i].name=MIvector_dimension;_map_to_std[0]=i;break;
+        //default: REPORT_ERROR("Unknown Dimension!");
+      }
+      mdims[i]=ncdimdef(_mincid, _info[i].name.c_str(), _info[i].length);
+      if(_info[i].dim!=dim_info::DIM_VEC)
+      {
+        int dimid=micreate_std_variable(_mincid,(char*)_info[i].name.c_str(),NC_INT, 0, NULL);
+        miattputdbl(_mincid, dimid, (char*)MIstep,_info[i].step);
+        miattputdbl(_mincid, dimid, (char*)MIstart,_info[i].start);
+        
+        if(_info[i].have_dir_cos)
+          ncattput(_mincid, dimid, (char*)MIdirection_cosines,NC_DOUBLE, 3, _info[i].dir_cos);
+      }
+    }
+    _slab_len=1;
+    for(int i=0;i<_slice_dimensions;i++)
+    {
+      _slab[_ndims-i-1]=_info[_ndims-i-1].length;
+      _slab_len*=_info[_ndims-i-1].length;
+    }
+    
+    _icmax=_icmin=MI_ERROR;
+    //ncopts = NC_OPTS_VAL;
+    _imgid=micreate_std_variable(_mincid, (char*)MIimage, _datatype, _ndims, mdims);
+    _image_range[0]=DBL_MAX;_image_range[1]=-DBL_MAX;
+    
+    switch(_datatype)
+    {
+      case NC_DOUBLE:
+        vrange[0]=-DBL_MAX;vrange[1]=DBL_MAX;
+        _is_signed=1;
+        break;
+      case NC_FLOAT:
+        vrange[0]=-FLT_MAX;vrange[1]=FLT_MAX;
+        _is_signed=1;
+        break;
+      case NC_SHORT:
+        if(_is_signed)
+        {
+          vrange[0]=SHRT_MIN;
+          vrange[1]=SHRT_MAX;
+        } else {
+          vrange[0]=0;vrange[1]=USHRT_MAX;
+        }
+        break;
+      case NC_BYTE:
+        if(_is_signed)
+        {
+          vrange[0]=-128;vrange[1]=127;
+        } else {
+          vrange[0]=0;vrange[1]=255;
+        }
+        break;
+      case NC_INT:
+        if(_is_signed)
+        {
+          vrange[0]=INT_MIN;vrange[1]=INT_MAX;
+        }else{
+          vrange[0]=0;vrange[1]=UINT_MAX;
+        }
+        break;
+      default:break;
+    };
+    miattputstr(_mincid, _imgid, (char*)MIcomplete, (char*)MI_FALSE);
+    miattputstr(_mincid, _imgid, (char*)MIsigntype, (char*)(_is_signed?MI_SIGNED:MI_UNSIGNED));
+    ncattput(_mincid, _imgid, (char*)MIvalid_range, NC_DOUBLE, 2, vrange);
+    miset_valid_range(_mincid, _imgid, vrange);
+  }
+  
+  void minc_1_writer::open(const char *path,const minc_1_base& imitate)
+  {
+    
+    open(path,imitate.info(),imitate.slice_dimensions(), 
+         imitate.datatype(),imitate.is_signed());
+    
+    copy_headers(imitate);
+  }
+  
+  void minc_1_writer::open(const char *path,const char *imitate_file)
+  {
+    minc_1_reader rdr;
+    //open minc file in metadate mode
+    rdr.open(imitate_file,false,true);
+    open(path,rdr);
+    //copy_headers(rdr);
+  }
+   
+  void minc_1_writer::setup_write_float()
+  {
+    _image_range[0]=DBL_MAX;_image_range[1]=-DBL_MAX;
+    
+    switch(_datatype)
+    {
+      case NC_DOUBLE:
+        _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+        _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+      
+        _set_image_range=true;
+        _set_slice_range=false;
+        break;
+      
+      case NC_FLOAT:
+        _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+        _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+      
+        _set_image_range=true;
+        _set_slice_range=false;
+        break;
+      
+      case NC_SHORT:
+        
+          _set_image_range=false;
+          _set_slice_range=true;
+        
+          _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+          _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        break;
+      
+      case NC_BYTE:
+        _set_image_range=false;
+        _set_slice_range=true;
+      
+        _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        break;
+      case NC_INT:
+        _set_image_range=false;
+        _set_slice_range=true;
+      
+        _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        break;
+      
+      default:
+        break;
+    };
+    ncendef(_mincid);
+    
+    if(_datatype==NC_DOUBLE || _datatype==NC_FLOAT)
+    {
+      miicv_setstr(_icvid, MI_ICV_SIGN,   (char*)MI_SIGNED);
+      miicv_setint(_icvid, MI_ICV_TYPE,    NC_FLOAT);
+      miicv_setint(_icvid, MI_ICV_DO_NORM,    true);
+      miicv_setint(_icvid, MI_ICV_USER_NORM, true);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MIN, -FLT_MAX);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MAX, FLT_MAX);
+      _calc_min_max=true;
+      
+    } else { //do something smart here?
+      miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_SIGNED);
+      miicv_setint(_icvid, MI_ICV_TYPE, NC_FLOAT);
+      miicv_setint(_icvid, MI_ICV_DO_NORM, false);
+      //miicv_setint(_icvid, MI_ICV_USER_NORM, false);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MIN, -FLT_MAX);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MAX, FLT_MAX);
+      _calc_min_max=true;
+      
+    }
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_FLOAT;
+    _write_prepared=true;
+  }
+  
+  void minc_1_writer::setup_write_double()
+  {
+    _image_range[0]=DBL_MAX;_image_range[1]=-DBL_MAX;
+    
+    switch(_datatype)
+    {
+      case NC_DOUBLE:
+        _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+        _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+      
+        _set_image_range=true;
+        _set_slice_range=false;
+        break;
+      
+      case NC_FLOAT:
+        _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+        _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+      
+        _set_image_range=true;
+        _set_slice_range=false;
+        break;
+      
+      case NC_SHORT:
+        
+          _set_image_range=false;
+          _set_slice_range=true;
+        
+          _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+          _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        break;
+      
+      case NC_BYTE:
+        _set_image_range=false;
+        _set_slice_range=true;
+      
+        _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        break;
+      case NC_INT:
+        _set_image_range=false;
+        _set_slice_range=true;
+      
+        _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, _ndims-_slice_dimensions, mdims);
+        break;
+      
+      default:
+        break;
+    };
+    ncendef(_mincid);
+    
+    if(_datatype==NC_DOUBLE)
+    {
+      miicv_setstr(_icvid, MI_ICV_SIGN,   (char*)MI_SIGNED);
+      miicv_setint(_icvid, MI_ICV_TYPE,    NC_DOUBLE);
+      miicv_setint(_icvid, MI_ICV_DO_NORM,    true);
+      miicv_setint(_icvid, MI_ICV_USER_NORM, true);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MIN, -DBL_MAX);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MAX, DBL_MAX);
+      _calc_min_max=true;
+      
+    } else if(_datatype==NC_FLOAT)  {
+      miicv_setstr(_icvid, MI_ICV_SIGN,   (char*)MI_SIGNED);
+      miicv_setint(_icvid, MI_ICV_TYPE,    NC_DOUBLE);
+      miicv_setint(_icvid, MI_ICV_DO_NORM,    true);
+      miicv_setint(_icvid, MI_ICV_USER_NORM, true);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MIN, -DBL_MAX);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MAX, DBL_MAX);
+      _calc_min_max=true;
+      
+    } else { //do something smart here?
+      miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_SIGNED);
+      miicv_setint(_icvid, MI_ICV_TYPE, NC_DOUBLE);
+      miicv_setint(_icvid, MI_ICV_DO_NORM, false);
+      //miicv_setint(_icvid, MI_ICV_USER_NORM, false);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MIN, -DBL_MAX);
+      miicv_setdbl(_icvid, MI_ICV_VALID_MAX, DBL_MAX);
+      _calc_min_max=true;
+      
+    }
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_DOUBLE;
+    _write_prepared=true;
+  }
+  
+  void minc_1_writer::setup_write_short(bool n)
+  {
+    _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+    _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+    _set_image_range=true;
+    _set_slice_range=false;
+    
+    ncendef(_mincid);
+    
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_SHORT);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_SIGNED);
+    //miicv_setstr(_icvid, MI_ICV_SIGN, true);    
+    /* Set range of values */ //TODO: set this to something sensible?
+    miicv_setint(_icvid, MI_ICV_VALID_MIN, SHRT_MIN);
+    miicv_setint(_icvid, MI_ICV_VALID_MAX, SHRT_MAX);
+
+    /* No normalization so that pixels are scaled to the slice */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, false);
+    miicv_setint(_icvid, MI_ICV_DO_RANGE, false);
+    
+    miicv_attach(_icvid, _mincid, _imgid);
+    
+    _io_datatype=NC_SHORT;
+    _write_prepared=true;
+  }
+  
+  void minc_1_writer::setup_write_ushort(bool n)
+  {
+    _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+    _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+    _set_image_range=true;
+    _set_slice_range=false;
+    
+    ncendef(_mincid);
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_SHORT);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_UNSIGNED);
+    miicv_setstr(_icvid, MI_ICV_SIGN, false); 
+    
+    /* Set range of values */ //TODO: set this to something sensible?
+    miicv_setint(_icvid, MI_ICV_VALID_MIN, 0);
+    miicv_setint(_icvid, MI_ICV_VALID_MAX, USHRT_MAX);
+
+    /* No normalization so that pixels are scaled to the slice */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, false);
+    miicv_setint(_icvid, MI_ICV_DO_RANGE, false);
+    
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_SHORT;
+    _write_prepared=true;
+  }
+  
+  void minc_1_writer::setup_write_byte(bool n)
+  {
+    _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+    _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+    _set_image_range=true;
+    _set_slice_range=false;
+    
+    ncendef(_mincid);
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_BYTE);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_UNSIGNED);
+
+    /* Set range of values */ //TODO: set this to something sensible?
+    miicv_setint(_icvid, MI_ICV_VALID_MIN, 0);
+    miicv_setint(_icvid, MI_ICV_VALID_MAX, UCHAR_MAX);
+
+    /* No normalization so that pixels are scaled to the slice */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, false);
+    miicv_setint(_icvid, MI_ICV_DO_RANGE, false);
+    
+    miicv_attach(_icvid, _mincid, _imgid);
+    
+    _io_datatype=NC_BYTE;
+    _write_prepared=true;
+  }
+  
+  void minc_1_writer::setup_write_int(bool n)
+  {
+    _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+    _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+    _set_image_range=true;
+    _set_slice_range=false;
+    
+    ncendef(_mincid);
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_INT);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_SIGNED);
+
+    /* Set range of values */ //TODO: set this to something sensible?
+    miicv_setint(_icvid, MI_ICV_VALID_MIN, INT_MIN);
+    miicv_setint(_icvid, MI_ICV_VALID_MAX, INT_MAX);
+
+    /* No normalization so that pixels are scaled to the slice */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, false);
+    miicv_setint(_icvid, MI_ICV_DO_RANGE, false);
+    
+    miicv_attach(_icvid, _mincid, _imgid);
+
+    
+    _io_datatype=NC_INT;
+    _write_prepared=true;
+  }
+  
+  void minc_1_writer::setup_write_uint(bool n)
+  {
+    _icmax=micreate_std_variable(_mincid, (char*)MIimagemax, NC_DOUBLE, 0, NULL);
+    _icmin=micreate_std_variable(_mincid, (char*)MIimagemin, NC_DOUBLE, 0, NULL);
+    _set_image_range=true;
+    _set_slice_range=false;
+    
+    ncendef(_mincid);
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_INT);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_UNSIGNED);
+
+    /* Set range of values */ //TODO: set this to something sensible?
+    miicv_setint(_icvid, MI_ICV_VALID_MIN, 0);
+    miicv_setint(_icvid, MI_ICV_VALID_MAX, UINT_MAX);
+
+    /* No normalization so that pixels are scaled to the slice */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, false);
+    miicv_setint(_icvid, MI_ICV_DO_RANGE, false);
+    
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_INT;
+    _write_prepared=true;
+  }
+  
+  void minc_1_reader::_setup_dimensions(void)
+  {
+    if(_metadate_only)
+      REPORT_ERROR("Minc file in metadate only mode!");
+    if(_positive_directions)
+    {
+      /* We want to ensure that images have X, Y and Z dimensions in the
+      positive direction, giving patient left on left and for drawing from
+      bottom up. If we wanted patient right on left and drawing from
+      top down, we would set to MI_ICV_NEGATIVE. */
+      
+      miicv_setint(_icvid, MI_ICV_DO_DIM_CONV, true);
+      //TODO: make sure to change only x,y,z conversions here
+      //miicv_setint(_icvid, MI_ICV_XDIM_DIR, 3);
+      //we want to convert only X,Y,Z dimensions if they are present
+      int num=(_map_to_std[1]>=0?1:0)+(_map_to_std[2]>=0?1:0)+(_map_to_std[3]>=0?1:0);
+      miicv_setint(_icvid, MI_ICV_NUM_IMGDIMS, num);
+      
+      if(_map_to_std[1]>=0) 
+      {
+        miicv_setint(_icvid, MI_ICV_DIM_SIZE+_map_to_std[1],-1);
+        miicv_setint(_icvid, MI_ICV_XDIM_DIR, MI_ICV_POSITIVE);
+      }
+      
+      if(_map_to_std[2]>=0) 
+      {
+        miicv_setint(_icvid, MI_ICV_DIM_SIZE+_map_to_std[2],-1);
+        miicv_setint(_icvid, MI_ICV_YDIM_DIR, MI_ICV_POSITIVE);
+      }
+      
+      if(_map_to_std[3]>=0) 
+      {
+        miicv_setint(_icvid, MI_ICV_DIM_SIZE+_map_to_std[3],-1);
+        miicv_setint(_icvid, MI_ICV_ZDIM_DIR, MI_ICV_POSITIVE);
+      }
+    }
+    miicv_setint(_icvid, MI_ICV_DO_SCALAR, false);
+  }
+  
+  void minc_1_reader::setup_read_float(void)
+  {
+    if(_metadate_only)
+      REPORT_ERROR("Minc file in metadate only mode!");
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_FLOAT);
+    miicv_setint(_icvid, MI_ICV_DO_NORM, true);
+    miicv_setint(_icvid, MI_ICV_USER_NORM, true);
+    /* Make sure that any out of range values are mapped to lowest value
+      of type (for input only) */
+    miicv_setint(_icvid, MI_ICV_DO_FILLVALUE, true);
+    
+    _setup_dimensions();
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_FLOAT;
+    _read_prepared=true;
+  }
+  
+  void minc_1_reader::setup_read_double(void)
+  {
+    if(_metadate_only)
+      REPORT_ERROR("Minc file in metadate only mode!");
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_DOUBLE);
+    miicv_setint(_icvid, MI_ICV_DO_NORM, true);
+    miicv_setint(_icvid, MI_ICV_USER_NORM, true);
+    /* Make sure that any out of range values are mapped to lowest value
+      of type (for input only) */
+    miicv_setint(_icvid, MI_ICV_DO_FILLVALUE, true);
+    
+    _setup_dimensions();
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_DOUBLE;
+    _read_prepared=true;
+  }
+
+  void minc_1_reader::setup_read_short(bool n)
+  {
+    if(_metadate_only)
+      REPORT_ERROR("Minc file in metadate only mode!");
+    
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_SHORT);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_SIGNED);
+    /* Set range of values */
+    miicv_setdbl(_icvid, MI_ICV_VALID_MIN, _image_range[0]);
+    miicv_setdbl(_icvid, MI_ICV_VALID_MAX, _image_range[1]);
+
+    /* Do normalization so that all pixels are on same scale */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, true);
+    //miicv_setint(_icvid, MI_ICV_USER_NORM, true);
+    /* Make sure that any out of range values are mapped to lowest value
+      of type (for input only) */
+    miicv_setint(_icvid, MI_ICV_DO_FILLVALUE, true);
+    
+    _setup_dimensions();
+    
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_SHORT;
+    _read_prepared=true;
+  }
+  
+  void minc_1_reader::setup_read_ushort(bool n)
+  {
+    if(_metadate_only)
+      REPORT_ERROR("Minc file in metadate only mode!");
+    
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_SHORT);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_UNSIGNED);
+    /* Set range of values */
+    miicv_setdbl(_icvid, MI_ICV_VALID_MIN, _image_range[0]);
+    miicv_setdbl(_icvid, MI_ICV_VALID_MAX, _image_range[1]);
+
+    /* Do normalization so that all pixels are on same scale */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, false);
+    //miicv_setint(_icvid, MI_ICV_USER_NORM, true);
+    /* Make sure that any out of range values are mapped to lowest value
+      of type (for input only) */
+    miicv_setint(_icvid, MI_ICV_DO_FILLVALUE, true);
+    
+    _setup_dimensions();
+    
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_SHORT;
+    _read_prepared=true;
+  }
+  
+  void minc_1_reader::setup_read_byte(bool n)
+  {
+    if(_metadate_only)
+      REPORT_ERROR("Minc file in metadate only mode!");
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_BYTE);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_UNSIGNED);
+    /* Set range of values */
+    miicv_setdbl(_icvid, MI_ICV_VALID_MIN, _image_range[0]);
+    miicv_setdbl(_icvid, MI_ICV_VALID_MAX, _image_range[1]);
+
+   /* Do normalization so that all pixels are on same scale */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, true);
+    /* Make sure that any out of range values are mapped to lowest value
+      of type (for input only) */
+    miicv_setint(_icvid, MI_ICV_DO_FILLVALUE, true);
+    
+    _setup_dimensions();
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_BYTE;
+    _read_prepared=true;
+  }
+  
+  void minc_1_reader::setup_read_int(bool n)
+  {
+    if(_metadate_only)
+      REPORT_ERROR("Minc file in metadate only mode!");
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_INT);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_SIGNED);
+    /* Set range of values */
+    miicv_setdbl(_icvid, MI_ICV_VALID_MIN, _image_range[0]);
+    miicv_setdbl(_icvid, MI_ICV_VALID_MAX, _image_range[1]);
+
+   /* Do normalization so that all pixels are on same scale */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, true);
+    /* Make sure that any out of range values are mapped to lowest value
+      of type (for input only) */
+    miicv_setint(_icvid, MI_ICV_DO_FILLVALUE, true);
+    
+    _setup_dimensions();
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_INT;
+    _read_prepared=true;
+  }
+  
+  void minc_1_reader::setup_read_uint(bool n)
+  {
+    if(_metadate_only)
+      REPORT_ERROR("Minc file in metadate only mode!");
+    miicv_setint(_icvid, MI_ICV_TYPE, NC_INT);
+    miicv_setstr(_icvid, MI_ICV_SIGN, (char*)MI_UNSIGNED);
+    /* Set range of values */
+    miicv_setdbl(_icvid, MI_ICV_VALID_MIN, _image_range[0]);
+    miicv_setdbl(_icvid, MI_ICV_VALID_MAX, _image_range[1]);
+
+   /* Do normalization so that all pixels are on same scale */
+    miicv_setint(_icvid, MI_ICV_DO_NORM, true);
+    /* Make sure that any out of range values are mapped to lowest value
+      of type (for input only) */
+    miicv_setint(_icvid, MI_ICV_DO_FILLVALUE, true);
+    
+    _setup_dimensions();
+    miicv_attach(_icvid, _mincid, _imgid);
+    _io_datatype=NC_INT;
+    _read_prepared=true;
+  }
+  
+  void minc_1_reader::read(void* buffer)
+  {
+    if(!_read_prepared)
+      REPORT_ERROR("Not ready to read, use setup_read_XXXX");
+
+    miicv_get(_icvid, &_cur[0], &_slab[0], buffer);
+  }
+  
+  void minc_1_writer::write(void* buffer)
+  {
+    if(!_write_prepared)
+      REPORT_ERROR("Not ready to write, use setup_write_XXXX");
+    
+    double r_min= DBL_MAX; //slab minimal value
+    double r_max=-DBL_MAX; //slab maximal value
+    //int irmin=0,irmax=0;
+    if(_calc_min_max )
+    {
+      if(_io_datatype==NC_FLOAT)
+      {// 
+        float *tmp=(float*)buffer;
+        for(int i=0;i<_slab_len;i++)
+        {
+          if(r_min>tmp[i]) r_min=tmp[i];//irmin=i;
+          if(r_max<tmp[i]) r_max=tmp[i];//irmax=i;
+        }
+      } else if(_io_datatype==NC_DOUBLE) {
+          double *tmp=(double*)buffer;
+          for(int i=0;i<_slab_len;i++)
+          {
+            if(r_min>tmp[i]) r_min=tmp[i];//irmin=i;
+            if(r_max<tmp[i]) r_max=tmp[i];//irmax=i;
+          }
+      } else if(_io_datatype==NC_SHORT && !_is_signed) {
+        unsigned short *tmp=(unsigned short *)buffer;
+        for(int i=0;i<_slab_len;i++)
+        {
+          if(r_min>tmp[i]) r_min=tmp[i];
+          if(r_max<tmp[i]) r_max=tmp[i];
+        }
+      } else if(_io_datatype==NC_SHORT && _is_signed) {
+        short *tmp=(short *)buffer;
+        for(int i=0;i<_slab_len;i++)
+        {
+          if(r_min>tmp[i]) r_min=tmp[i];
+          if(r_max<tmp[i]) r_max=tmp[i];
+        }
+      } else if(_io_datatype==NC_BYTE) {
+        unsigned char *tmp=(unsigned char *)buffer;
+        for(int i=0;i<_slab_len;i++)
+        {
+          if(r_min>tmp[i]) r_min=tmp[i];
+          if(r_max<tmp[i]) r_max=tmp[i];
+        }
+      } else if(_io_datatype==NC_INT && _is_signed) {
+        int *tmp=(int *)buffer;
+        for(int i=0;i<_slab_len;i++)
+        {
+          if(r_min>tmp[i]) r_min=tmp[i];
+          if(r_max<tmp[i]) r_max=tmp[i];
+        }
+      } else if(_io_datatype==NC_INT && !_is_signed) {
+        unsigned int *tmp=(unsigned int *)buffer;
+        for(int i=0;i<_slab_len;i++)
+        {
+          if(r_min>tmp[i]) r_min=tmp[i];
+          if(r_max<tmp[i]) r_max=tmp[i];
+        }
+      }
+      /*
+      if(r_min<-10000||r_max>10000)
+      {
+        std::cerr<<r_min<<":"<<r_max<<" ";
+        for(int i=0;i<4;i++)
+          std::cerr<<_cur[i]<<",";
+        std::cerr<<"  "<<r_min<<":"<<r_max;
+        std::cerr<<" "<<irmin<<":"<<irmax<<"   "<<_slab_len;
+        std::cerr<<std::endl;
+      }*/
+      
+      if(_set_slice_range)
+      {
+        miicv_detach(_icvid);
+        miicv_setdbl(_icvid, MI_ICV_VALID_MIN, r_min);
+        miicv_setdbl(_icvid, MI_ICV_VALID_MAX, r_max);
+        miicv_attach(_icvid, _mincid, _imgid);
+      }
+      
+      if(_set_slice_range)
+      {
+        mivarput1(_mincid, _icmin, &_cur[0], NC_DOUBLE, NULL, &r_min);
+        mivarput1(_mincid, _icmax, &_cur[0], NC_DOUBLE, NULL, &r_max);
+      }
+      
+      if(_image_range[0]>r_min) _image_range[0]=r_min;
+      if(_image_range[1]<r_max) _image_range[1]=r_max;
+    }
+    miicv_put(_icvid, &_cur[0], &_slab[0], buffer);
+  }
+  
+  minc_1_writer::~minc_1_writer()
+  {
+    if(_set_image_range)
+    {
+      mivarput1(_mincid, _icmin, 0, NC_DOUBLE, NULL, &_image_range[0]);
+      mivarput1(_mincid, _icmax, 0, NC_DOUBLE, NULL, &_image_range[1]);
+      miset_valid_range(_mincid, _imgid, _image_range);
+    }
+  }
+  
+  void minc_1_writer::copy_headers(const minc_1_base& src)
+  {
+    
+    //code copied from mincresample
+    int nexcluded, excluded_vars[10];
+    int varid;
+    
+    /* Create the list of excluded variables */
+    nexcluded = 0;
+    //ncopts = 0;
+
+    if ((varid=ncvarid(src.mincid(), MIxspace)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+    if ((varid=ncvarid(src.mincid(), MIyspace)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+    if ((varid=ncvarid(src.mincid(), MIzspace)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+    if ((varid=ncvarid(src.mincid(), MItime)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+    if ((varid=ncvarid(src.mincid(), MIimage)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+    if ((varid=ncvarid(src.mincid(), MIimagemax)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+    if ((varid=ncvarid(src.mincid(), MIimagemin)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+    if ((varid=ncvarid(src.mincid(), "rootvariable")) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+//#if MINC2
+    if ((varid=ncvarid(src.mincid(), MIvector_dimension)) != MI_ERROR)
+      excluded_vars[nexcluded++] = varid;
+//#endif /* MINC2 */
+    //ncopts = NC_VERBOSE | NC_FATAL;
+    /* Copy all other variable definitions */
+    micopy_all_var_defs(src.mincid(), _mincid, nexcluded, excluded_vars);
+  }
+  
+  //! append a line into minc history
+  void minc_1_writer::append_history(const char *append_history)
+  {
+    nc_type datatype;
+    int att_length;
+    //ncopts=0;
+    if ((ncattinq(_mincid, NC_GLOBAL, MIhistory, &datatype,&att_length) == MI_ERROR) ||
+        (datatype != NC_CHAR))
+      att_length = 0;
+    att_length += strlen(append_history) + 1;
+    char* str = new char[att_length];
+    str[0] = '\0';
+    miattgetstr(_mincid, NC_GLOBAL, (char*)MIhistory, att_length,str);
+    //ncopts=NC_VERBOSE | NC_FATAL;
+    strcat(str, append_history);
+    miattputstr(_mincid, NC_GLOBAL, (char*)MIhistory, str);
+    delete [] str;
+  }
+  
+  int minc_1_base::create_var_id(const char *varname)
+  {
+    int old_ncopts = ncopts; ncopts = 0;
+    int res=var_id(varname);
+    if(res==MI_ERROR) //need to create a variable
+      res=micreate_group_variable(_mincid,(char*)varname);//ncvardef(_mincid,varname,NC_INT,0,0);
+    if(res==MI_ERROR) //need to create a variable
+      res=ncvardef(_mincid,varname,NC_INT,0,0);
+    ncopts = old_ncopts;
+    return res;
+  }
+      
+  void minc_1_base::insert(const char *varname,const char *attname,double val)
+  {
+    ncattput(_mincid, create_var_id(varname),attname, NC_DOUBLE, 1, (void *) &val);
+  }
+  
+  void minc_1_base::insert(const char *varname,const char *attname,const char* val)
+  {
+    ncattput(_mincid, create_var_id(varname),attname, NC_CHAR, strlen(val) + 1, (void *) val);
+  }
+  
+  void minc_1_base::insert(const char *varname,const char *attname,const std::vector<double> &val)
+  {
+    ncattput(_mincid, create_var_id(varname),attname, NC_DOUBLE, val.size(), (void *) &val[0]);
+  }
+  
+  void minc_1_base::insert(const char *varname,const char *attname,const std::vector<int> &val)
+  {
+    ncattput(_mincid, create_var_id(varname),attname, NC_INT, val.size(), (void *) &val[0]);
+  }
+  
+  void minc_1_base::insert(const char *varname,const char *attname,const std::vector<short> &val)
+  {
+    ncattput(_mincid, create_var_id(varname),attname, NC_SHORT, val.size(), (void *) &val[0]);
+  }
+  
+  void minc_1_base::insert(const char *varname,const char *attname,const std::vector<unsigned char> &val)
+  {
+    ncattput(_mincid, create_var_id(varname),attname, NC_BYTE, val.size(), (void *) &val[0]);
+  }
+  
+};
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_1_rw.h
@@ -0,0 +1,391 @@
+#ifndef __MINC_1_RW__
+#define __MINC_1_RW__
+
+#include <vector>
+#include <string>
+
+#include "minc_io_exceptions.h"
+//#include "minc_io_fixed_vector.h"
+
+#ifdef USE_MINC2
+#define MINC2 1
+#endif 
+
+extern "C" {
+#include <minc.h> 
+}
+
+#include <typeinfo>
+#include <float.h>
+#include <iostream>
+
+namespace minc
+{
+  
+  //! class for storing dimension information 
+  struct dim_info
+  {
+    enum dimensions {DIM_UNKNOWN=0,DIM_X,DIM_Y,DIM_Z,DIM_TIME,DIM_VEC} ;
+    dim_info():length(0),step(0),start(0),have_dir_cos(false)
+    {
+      dir_cos[0]=dir_cos[1]=dir_cos[2]=0.0;
+    }
+    dim_info(int l, double sta,double spa,dimensions d,bool hd=false);
+    size_t length;
+    double step,start;
+    bool have_dir_cos;
+    double dir_cos[3];
+    std::string name;
+    dimensions  dim;
+  };
+  
+  //! collection of dimensions describing a minc file
+  typedef std::vector<dim_info> minc_info;
+  
+  //! minc file rw base class
+  class minc_1_base
+  {
+  protected:
+    int _slab_len;
+    int _icvid;
+    std::vector<long> _cur,_slab;
+    size_t  _slice_dimensions;
+    bool _last;
+    bool _positive_directions;
+    nc_type _datatype;
+    nc_type _io_datatype;
+    char _dimension_names[MAX_VAR_DIMS][MAX_NC_NAME];
+    std::vector<double> _dir_cos;
+    long vcount[MAX_VAR_DIMS];
+    std::vector<double> _world_matrix;
+    std::vector<int>    _voxel_matrix;
+    int _ndims, mdims[MAX_VAR_DIMS];
+    int _is_signed;
+    int _mincid, _imgid;
+    int _icmax,_icmin;
+    double _image_range[2];
+    std::vector<long> _dims;
+    std::vector<int> _map_to_std;
+    minc_info _info;
+    bool _minc2;
+  public:
+    
+    //! get the minc handle
+    int mincid(void) const  //this is not really a const ?
+    {
+      return _mincid;
+    }
+    
+    //! get the data type id (NC_BYTE,NC_INT etc)
+    nc_type datatype(void) const
+    {
+      return _datatype;
+    }
+    
+    //! byte size of the volume elements
+    unsigned int element_size(void) const
+    {
+      switch(_io_datatype)
+      {
+        case NC_FLOAT: return sizeof(float);
+        case NC_DOUBLE: return sizeof(double);
+        case NC_SHORT: return sizeof(short);
+        case NC_BYTE: return sizeof(char);
+        default:return 0;//maybe throw exception here?
+      }
+    }
+    
+    //! is data stored in signed format
+    bool is_signed(void) const
+    {
+      return _is_signed;
+    }
+  
+    //! constructor
+	  minc_1_base();
+
+    //! destructor, closes minc file
+    virtual ~minc_1_base();
+    
+    //! close the minc file
+    virtual void close();
+
+    //! is last slice was read?
+    bool last(void) const 
+    {
+      return _last;
+    }
+    
+    //! go to the beginning of file
+    void begin(void)
+    {
+      fill(_cur.begin(),_cur.end(),0);
+      _last=false;
+    }
+    
+    //! advance to next slice 
+    bool next_slice(void)
+    {
+      if(_last) return !_last;
+        
+      for(int i=_ndims-_slice_dimensions-1;i>=0;i--)
+      {
+        _cur[i]++;
+        if(_cur[i]<static_cast<long>(_info[i].length))
+          break;
+        if(!i)
+          _last=true;
+        else 
+          _cur[i]=0;
+      }
+      return !_last;
+    }
+    
+    //! slice length in elements
+    int slice_len(void) const
+    {
+      return _slab_len;
+    }
+    
+    //! number of dimensions
+    int dim_no(void) const
+    {
+      return _ndims;
+    }
+    
+    //! get the dimension information
+    const dim_info& dim(unsigned int n) const
+    {
+      if(n>=static_cast<unsigned int>(_ndims)) 
+	REPORT_ERROR("Dimension is not defined");
+      return _info[n];
+    }
+    
+    //! get the pointer to the dimension description array
+    const minc_info& info(void) const
+    {
+      return _info;
+    }
+    
+    //! get the number of dimensions in one slice
+    int slice_dimensions(void) const
+    {
+      return _slice_dimensions;
+    }
+    
+    //! get the current slice index
+    const std::vector<long> & current_slice(void) const
+    {
+      return _cur;
+    }
+    
+    //! get the normalized dimensions sizes 
+    //! ( 0 - vector_dimension, 1 - x, 2- y , 3 -z , 4 - time)
+    int ndim(int i) const
+    {
+      int j=_map_to_std[i];
+      if(j>=0) return _info[j].length;
+      return 0;
+    }
+    //! get normalized dimension start coordinate (see ndim)
+    double nstart(int i) const
+    {
+      int j=_map_to_std[i];
+      if(j>=0) return _info[j].start;
+      return 0.0;
+    }
+    
+    //! get normalized dimension spacing  (see ndim)
+    double nspacing(int i) const
+    {
+      int j=_map_to_std[i];
+      if(j>=0) return _info[j].step;
+      return 0.0;
+    }
+    
+    //! get normalized dimension direction cosine component  (see ndim)
+    double ndir_cos(int i,int j) const
+    {
+      int k=_map_to_std[i];
+      if(k>=0) return _info[k].dir_cos[j];
+      return 0.0;
+    }
+    
+    //! check if a normalized dimension has direction cosine information
+    bool have_dir_cos(int i) const
+    {
+      int k=_map_to_std[i];
+      if(k>=0) return _info[k].have_dir_cos;
+      return false;
+    }
+     
+    //! map file dimensions into normalized dimensions
+    int map_space(int i)
+    {
+      return _map_to_std[i];
+    }
+    
+    //metadate info handling function:
+    //! read the minc history (:history attribute)
+    std::string history(void) const;
+    
+    //! retrive var id, if it exists, otherwise return MI_ERROR
+    int var_id(const char *var_name) const;
+    
+    //! get variable length
+    long var_length(const char *var_name) const;
+    
+    //! get variable length
+    long var_length(int var_id) const;
+    
+    //! read the number of variables
+    int var_number(void) const;
+    
+    //! get the variable name number no
+    std::string var_name(int no) const;
+    
+    //! get the number of attributes associated with variable
+    int att_number(const char *var_name) const;
+    
+    //! get the number of attributes associated with variable
+    int att_number(int var_no) const;
+    
+    //! get the attribute name, given the number
+    std::string att_name(const char *var_name,int no) const;
+    //! get the attribute name, given the number
+    std::string att_name(int varid,int no) const;
+    
+    //! get the string attribute value , given the name
+    std::string att_value_string(const char *var_name,const char *att_name) const;
+    //! get the string attribute value , given variable id
+    std::string att_value_string(int varid,const char *att_name) const;
+    
+    //! get the double attribute value , given the name
+    std::vector<double> att_value_double(const char *var_name,const char *att_name) const;
+    //! get the int attribute value , given the name
+    std::vector<int> att_value_int(const char *var_name,const char *att_name) const;
+    //! get the short attribute value , given the variable id
+    std::vector<short> att_value_short(const char *var_name,const char *att_name) const;
+    //! get the byte attribute value , given the variable id
+    std::vector<unsigned char> att_value_byte(const char *var_name,const char *att_name) const;
+    
+    //! get the double attribute value , given the variable id
+    std::vector<double> att_value_double(int varid,const char *att_name) const;
+    //! get the int attribute value , given the variable id
+    std::vector<int> att_value_int(int varid,const char *att_name) const;
+    //! get the short attribute value , given the variable id
+    std::vector<short> att_value_short(int varid,const char *att_name) const;
+    //! get the byte attribute value , given the variable id
+    std::vector<unsigned char> att_value_byte(int varid,const char *att_name) const;
+    
+    //! enquire about attribute data type
+    nc_type att_type(const char *var_name,const char *att_name) const;
+    //! enquire about attribute data type
+    nc_type att_type(int varid,const char *att_name) const;
+
+    //! enquire about attribute length
+    int att_length(const char *var_name,const char *att_name) const;
+    //! enquire about attribute length
+    int att_length(int varid,const char *att_name) const;
+
+
+    //! return var_id for the given name (create one, if it doesn't exists)
+    int create_var_id(const char *varname);
+    
+    void insert(const char *varname,const char *attname,double val);
+    void insert(const char *varname,const char *attname,const char* val);
+    void insert(const char *varname,const char *attname,const std::vector<double> &val);
+    void insert(const char *varname,const char *attname,const std::vector<int> &val);
+    void insert(const char *varname,const char *attname,const std::vector<short> &val);
+    void insert(const char *varname,const char *attname,const std::vector<unsigned char> &val);
+    
+    
+    //! check if the file in MINC2 format
+    bool is_minc2(void) const
+    {
+      return _minc2;
+    }
+    
+  };
+  
+  //! minc file reader
+  class minc_1_reader:public minc_1_base
+  {
+    protected:
+      bool _metadate_only;
+      std::string _tempfile;
+      bool _have_temp_file;
+      bool _read_prepared;
+      void _setup_dimensions(void);
+
+    public:
+    //! copy constructor
+    minc_1_reader(const minc_1_reader&);
+    
+    //! default constructor
+    minc_1_reader();
+    
+    //! destructor
+    virtual ~minc_1_reader();
+    //! open a minc file
+    void open(const char *path,bool positive_directions=false,bool metadate_only=false,bool rw=false);
+    
+    //! read single slice
+    void read(void* slice);
+    //! setup reading in float format
+    void setup_read_float(void);
+    //! setup reading in double format
+    void setup_read_double(void);
+    //! setup reading in signed short format
+    void setup_read_short(bool normalized=false);
+    //! setup reading in unsigned short format
+    void setup_read_ushort(bool normalized=false);
+    //! setup reading in byte format
+    void setup_read_byte(bool normalized=false);
+    //! setup reading in int format
+    void setup_read_int(bool normalized=false);
+    //! setup reading in unsigned int format
+    void setup_read_uint(bool normalized=false);
+  };
+  
+  //! minc file writer
+  class minc_1_writer:public minc_1_base
+  {
+    protected:
+      bool _set_image_range;
+      bool _set_slice_range;
+      bool _calc_min_max;
+      bool _write_prepared;
+    public:
+      void open(const char *path,const minc_info& inf,int slice_dimensions,nc_type datatype,int __signed=0);
+      void open(const char *path,const minc_1_base& imitate);
+      void open(const char *path,const char *imitate_file);
+    
+      void setup_write_float(void);
+      void setup_write_double(void);
+      void setup_write_short(bool normalize=false);
+      void setup_write_ushort(bool normalize=false);
+      void setup_write_byte(bool normalize=false);
+      void setup_write_int(bool normalize=false);
+      void setup_write_uint(bool normalize=false);
+    
+      //! copy header from another minc file
+      void copy_headers(const minc_1_base& src);
+    
+      //! append a line into minc history
+      void append_history(const char *append_history);
+      
+      
+      //! constructor
+      minc_1_writer();
+      
+      minc_1_writer(const minc_1_writer&);
+      
+      //! destructor
+      virtual ~minc_1_writer();
+      
+      //!write a single slice, size of the buffer should be more or equall to slab_len
+      void write(void* slice);
+  };
+};
+#endif //__PRIMITIVE_MINC_IO__
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_1_simple.h
@@ -0,0 +1,290 @@
+#ifndef __MINC_1_SIMPLE_H__
+#define __MINC_1_SIMPLE_H__
+
+#include "minc_1_rw.h"
+
+namespace minc
+{
+  
+  template <class T> class minc_input_iterator
+  {
+    protected:
+      mutable minc_1_reader* _rw;
+      std::vector<T> _buf;
+      std::vector<long> _cur;
+      bool _last;
+      size_t _count;
+    public:
+      
+    const std::vector<long>& cur(void) const
+    {
+      return _cur;
+    }
+    
+    
+    minc_input_iterator(const minc_input_iterator<T>& a):_rw(a._rw),_cur(a._cur),_last(a._last),_count(a._count)
+    {
+    }
+    
+    minc_input_iterator(minc_1_reader& rw):_rw(&rw),_last(false),_count(0)
+    {
+    }
+    
+    minc_input_iterator():_rw(NULL),_last(false),_count(0)
+    {
+    }
+    
+    void attach(minc_1_reader& rw)
+    {
+      _rw=&rw;
+      _last=false;
+      _count=0;
+    }
+    
+    bool next(void)
+    {
+      if(_last) return false;
+      _count++;
+      for(size_t i=static_cast<size_t>(_rw->dim_no()-1);
+	  i>static_cast<size_t>(_rw->dim_no()-_rw->slice_dimensions()-1);i--)
+      {
+        _cur[i]++;
+        if(_cur[i]<static_cast<long>(_rw->dim(i).length))
+          break;
+        if(i>static_cast<size_t>(_rw->dim_no()-_rw->slice_dimensions())) 
+          _cur[i]=0;
+        else
+        {
+          //move to next slice 
+          if(i==0) // the case when slice_dimensions==dim_no
+          {
+            _last=true;
+            _count=0;
+            break;
+          }
+          if(!_rw->next_slice())
+          {
+            _last=true;
+            break;
+          }
+          _rw->read(&_buf[0]);
+          _cur=_rw->current_slice();
+          _count=0;
+          break;
+        }
+      }
+      return !_last;
+    }
+    
+    bool last(void)
+    {
+      return _last;
+    }
+    
+    void begin(void)
+    {
+      _cur.resize(MAX_VAR_DIMS,0);
+      _buf.resize(_rw->slice_len());
+      _count=0;
+      _rw->begin();
+      _rw->read(&_buf[0]);
+      _cur=_rw->current_slice();
+    }
+    
+    const T& value(void) const
+    {
+      return _buf[_count];
+    }
+  };
+  
+  template <class T> class minc_output_iterator
+  {
+    protected:
+      mutable minc_1_writer* _rw;
+      std::vector<T> _buf;
+      std::vector<long> _cur;
+      bool _last;
+      size_t _count;
+    public:
+    const std::vector<long>& cur(void) const
+    {
+      return _cur;
+    }
+    
+    minc_output_iterator(const minc_output_iterator<T>& a):_rw(a._rw),_cur(a._cur),_last(a._last),_count(a._count)
+    {
+    }
+    
+    minc_output_iterator(minc_1_writer& rw):_rw(&rw),_last(false),_count(0)
+    {
+      _buf.resize(rw.slice_len()); 
+    }
+    
+    minc_output_iterator():_rw(NULL),_last(false),_count(0)
+    {
+    }
+    
+    void attach(minc_1_writer& rw)
+    {
+      _rw=&rw;
+      _last=false;
+      _count=0;
+    }
+    
+    ~minc_output_iterator()
+    {
+      if(_count && !_last)
+        _rw->write(&_buf[0]);
+    }
+    
+    bool next(void)
+    {
+      if(_last) return false;
+      _count++;
+      for(int i=_rw->dim_no()-1;i>(_rw->dim_no()-_rw->slice_dimensions()-1);i--)
+      {
+        _cur[i]++;
+        if(_cur[i]<static_cast<long>(_rw->dim(i).length))
+          break;
+        if(i>(_rw->dim_no()-_rw->slice_dimensions())) 
+          _cur[i]=0;
+        else
+        {
+          //write slice into minc file
+          _rw->write(&_buf[0]);
+          _count=0;
+          //move to next slice 
+          if(i==0) // the case when slice_dimensions==dim_no
+          {
+            _last=true;
+            return false;
+          }
+          if(!_rw->next_slice())
+          {
+            _last=true;
+            break;
+          }
+          _cur=_rw->current_slice();
+          break;
+        }
+      }
+      return !_last;
+    }
+    
+    bool last(void)
+    {
+      return _last;
+    }
+    
+    void begin(void)
+    {
+      _buf.resize(_rw->slice_len());
+      _cur.resize(MAX_VAR_DIMS,0);
+      _count=0;
+      _rw->begin();
+      _cur=_rw->current_slice();
+    }
+    
+    void value(const T& v) 
+    {
+      _buf[_count]=v;
+    }
+  };
+  
+  //! will attempt to laod the whole volume in T Z Y X V order into buffer, file should be prepared (setup_read_XXXX)
+  template<class T> void load_standard_volume(minc_1_reader& rw, T* volume)
+  {
+    std::vector<size_t> strides(MAX_VAR_DIMS,0);
+    size_t str=1;
+    for(size_t i=0;i<5;i++)
+    {      
+      if(rw.map_space(i)<0) continue;
+      strides[rw.map_space(i)]=str;
+      str*=rw.ndim(i);
+    }
+
+    minc_input_iterator<T> in(rw);
+    for(in.begin();!in.last();in.next())
+    {
+      size_t address=0;
+      for(size_t i=0;i<static_cast<size_t>(rw.dim_no());i++)
+        address+=in.cur()[i]*strides[i];
+        
+      volume[address]=in.value();
+    }
+  }
+  
+  //! will attempt to save the whole volume in T Z Y X V order from buffer, file should be prepared (setup_read_XXXX)
+  template<class T> void save_standard_volume(minc_1_writer& rw, const T* volume)
+  {
+    std::vector<size_t> strides(MAX_VAR_DIMS,0);
+    size_t str=1;
+    for(size_t i=0;i<5;i++)
+    {      
+      if(rw.map_space(i)<0) continue;
+      strides[rw.map_space(i)]=str;
+      str*=rw.ndim(i);
+    }
+    
+    minc_output_iterator<T> out(rw);
+    for(out.begin();!out.last();out.next())
+    {
+      size_t address=0;
+      for(size_t i=0;i<static_cast<size_t>(rw.dim_no());i++)
+        address+=out.cur()[i]*strides[i];
+        
+      out.value(volume[address]);
+    }
+  }
+
+  //! will attempt to load the whole volume in Z Y X T V  order into buffer, file should be prepared (setup_read_XXXX)
+  template<class T> void load_non_standard_volume(minc_1_reader& rw, T* volume)
+  {
+    std::vector<size_t> strides(MAX_VAR_DIMS,0);
+    size_t str=1;
+    const size_t dimorder[]={0,4,1,2,3};
+    for(size_t i=0;i<5;i++)
+    {
+      if(rw.map_space(dimorder[i])<0|| !rw.ndim(dimorder[i]) ) continue;
+      strides[rw.map_space(dimorder[i])]=str;
+      str*=rw.ndim(dimorder[i]);
+    }
+    
+    minc_input_iterator<T> in(rw);
+    for(in.begin();!in.last();in.next())
+    {
+      size_t address=0;
+      for(size_t i=0;i<rw.dim_no();i++)
+        address+=in.cur()[i]*strides[i];
+      
+      volume[address]=in.value();
+    }
+  }
+  
+  //! will attempt to save the whole volume in V T Z Y X order from buffer, file should be prepared (setup_read_XXXX)
+  template<class T> void save_non_standard_volume(minc_1_writer& rw, const T* volume)
+  {
+    std::vector<size_t> strides(MAX_VAR_DIMS,0);
+    size_t str=1;
+    const size_t dimorder[]={0,4,1,2,3};
+    for(size_t i=0;i<5;i++)
+    {
+      if(rw.map_space(dimorder[i])<0 || !rw.ndim(dimorder[i]) ) continue;
+      strides[rw.map_space(dimorder[i])]=str;
+      str*=rw.ndim(dimorder[i]);
+    }
+    minc_output_iterator<T> out(rw);
+    for(out.begin();!out.last();out.next())
+    {
+      size_t address=0;
+      for(size_t i=0;i<rw.dim_no();i++)
+        address+=out.cur()[i]*strides[i];
+
+      out.value(volume[address]);
+    }
+  }
+  
+  
+};//minc
+
+#endif //__MINC_1_SIMPLE_H__
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_1_simple_rw.cpp
@@ -0,0 +1,53 @@
+#include <iostream>
+#include <math.h>
+
+#include "minc_1_simple_rw.h"
+
+namespace minc
+{
+
+  const double minc_eps=1e-5;
+  
+  bool is_same(minc_1_reader& one,minc_1_reader& two,bool verbose)
+  {
+    if(one.dim_no()!=two.dim_no())
+    {
+      if(verbose)
+        std::cerr<<"Unequal number of dimensions !"<<std::endl;
+      return false;
+    }
+    for(int j=0;j<5;j++)
+    {
+      if(one.ndim(j)!=two.ndim(j))
+      {
+        if(verbose)
+          std::cerr<<"Unequal dimension sizes"<<std::endl;
+        return false;
+      }
+      
+      if(fabs(one.nstart(j)-two.nstart(j))>minc_eps)
+      {
+        if(verbose)
+          std::cerr<<"Unequal dimension sarts"<<std::endl;
+        return false;
+      }
+      
+      if(fabs(one.nspacing(j)-two.nspacing(j))>minc_eps)
+      {
+        if(verbose)
+          std::cerr<<"Unequal dimension steps"<<std::endl;
+        return false;
+      }
+      
+      for(int i=0;i<3;i++)
+        if(fabs(one.ndir_cos(j,i)-two.ndir_cos(j,i))>minc_eps)
+        {
+          if(verbose)
+            std::cerr<<"Unequal direction cosines"<<std::endl;
+          return false;
+        }
+    }
+    return true;
+  }
+
+};
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_1_simple_rw.h
@@ -0,0 +1,334 @@
+#ifndef __MINC_1_SIMPLE_RW_H__
+#define __MINC_1_SIMPLE_RW_H__
+
+#include "minc_1_simple.h"
+#include "minc_io_simple_volume.h"
+#include "minc_io_fixed_vector.h"
+#include "minc_io_4d_volume.h"
+
+namespace minc
+{
+  
+  template<class T> void load_simple_volume(minc_1_reader& rw,simple_volume<T>& vol)
+  {
+    if(rw.ndim(1)<=0||rw.ndim(2)<=0||rw.ndim(3)<=0||rw.ndim(4)>0) 
+      REPORT_ERROR("Need 3D minc file");
+    
+    vol.resize(rw.ndim(1),rw.ndim(2),rw.ndim(3));
+     
+    if(typeid(T)==typeid(unsigned char))
+    {
+      rw.setup_read_byte();
+      load_standard_volume(rw,vol.c_buf());
+    }
+    else if(typeid(T)==typeid(int))
+    {
+      rw.setup_read_int();
+      load_standard_volume(rw,vol.c_buf());
+    }
+    else if(typeid(T)==typeid(fixed_vec<3,float>))
+    {
+      rw.setup_read_float(); 
+      load_standard_volume<float>(rw,(float*)vol.c_buf());
+    }
+    else if(typeid(T)==typeid(float))
+    {
+      rw.setup_read_float(); 
+      load_standard_volume(rw,vol.c_buf());
+    }
+    else if(typeid(T)==typeid(fixed_vec<3,double>))
+    {
+      rw.setup_read_double(); 
+      load_standard_volume<double>(rw,(double*)vol.c_buf());
+    }
+    else if(typeid(T)==typeid(double))
+    {
+      rw.setup_read_double(); 
+      load_standard_volume(rw,vol.c_buf());
+    } else 
+			REPORT_ERROR("Data type not supported for minc io");
+    
+    //set coordinate transfer parameters
+    for(int i=0;i<3;i++)
+    {
+      vol.step()[i]=rw.nspacing(i+1);
+      vol.start()[i]=rw.nstart(i+1);
+      
+      if(rw.have_dir_cos(i+1))
+      {
+        for(int j=0;j<3;j++)
+          vol.direction_cosines(i)[j]=rw.ndir_cos(i+1,j);
+      } else {
+        for(int j=0;j<3;j++)
+          vol.direction_cosines(i)[j]=(i==j?1.0:0.0); //identity
+      }
+    }
+  }
+  
+  template<class T> void save_simple_volume(minc_1_writer& rw,const simple_volume<T>& vol)
+  {
+    if(typeid(T)==typeid(unsigned char))
+    {
+      rw.setup_write_byte();
+      save_standard_volume(rw,vol.c_buf());
+    }
+    else if(typeid(T)==typeid(int))
+    {
+      rw.setup_write_int();
+      save_standard_volume(rw,vol.c_buf());
+    }
+    else if(typeid(T)==typeid(fixed_vec<3,float>))
+    {
+      rw.setup_write_float(); 
+      save_standard_volume<float>(rw,(float*)vol.c_buf());
+    }
+    else if(typeid(T)==typeid(float))
+    {
+      rw.setup_write_float(); 
+      save_standard_volume(rw,vol.c_buf());
+    }
+    else if(typeid(T)==typeid(fixed_vec<3,double>))
+    {
+      rw.setup_write_double(); 
+      save_standard_volume<double>(rw,(double*)vol.c_buf());
+    }
+    else if(typeid(T)==typeid(double))
+    {
+      rw.setup_write_double(); 
+      save_standard_volume(rw,vol.c_buf());
+    }
+    else 
+			REPORT_ERROR("Data type not supported for minc io");
+  }
+  
+  
+  template<class T> void load_4d_volume(minc_1_reader& rw,simple_4d_volume<T>& vol)
+  {
+    //if(rw.ndim(1)<=0||rw.ndim(2)<=0||rw.ndim(3)<=0||rw.ndim(4)<=0) 
+    //  REPORT_ERROR("Need 4D minc file");
+    
+    vol.resize(rw.ndim(1),rw.ndim(2),rw.ndim(3),rw.ndim(4)>0?rw.ndim(4):1); //always assume 4 dimensions
+     
+    if(typeid(T)==typeid(unsigned char))
+      rw.setup_read_byte();
+    else if(typeid(T)==typeid(int))
+      rw.setup_read_int();
+    else if(typeid(T)==typeid(fixed_vec<3,float>))
+      rw.setup_read_float(); 
+    else if(typeid(T)==typeid(float))
+      rw.setup_read_float(); 
+    else if(typeid(T)==typeid(fixed_vec<3,double>))
+      rw.setup_read_double(); 
+    else if(typeid(T)==typeid(double))
+      rw.setup_read_double();
+		else 
+			REPORT_ERROR("Data type not supported for minc io");
+    
+    std::vector<size_t> strides(MAX_VAR_DIMS,0);
+    size_t str=1;
+    
+    for(size_t i=0;i<5;i++) //T is a special case
+    {      
+      if(rw.map_space(i)<0) continue;
+      strides[rw.map_space(i)]=str;
+      str*=rw.ndim(i);
+    }
+    
+    if(rw.map_space(4)>=0)
+      strides[rw.map_space(4)]=0; //t dimension
+
+    minc_input_iterator<T> in(rw);
+    for(in.begin();!in.last();in.next())
+    {
+      size_t address=0;
+      size_t slice=0;
+      for(size_t i=0;i<rw.dim_no();i++)
+      {
+        if(strides[i]>0)
+          address+=in.cur()[i]*strides[i];
+        else //
+          slice=in.cur()[i];
+      }
+      vol.frame(slice).c_buf()[address]=in.value();
+    }
+    
+    //set coordinate transfer parameters
+    for(int i=0;i<3;i++)
+    {
+      vol.step()[i]=rw.nspacing(i+1);
+      vol.start()[i]=rw.nstart(i+1);
+      
+      if(rw.have_dir_cos(i+1))
+      {
+        for(int j=0;j<3;j++)
+          vol.direction_cosines(i)[j]=rw.ndir_cos(i+1,j);
+      } else {
+        for(int j=0;j<3;j++)
+          vol.direction_cosines(i)[j]=(i==j?1.0:0.0); //identity
+      }
+    }
+    if(rw.ndim(4)>0)
+    {
+      vol.t_start()=rw.nstart(4);//T
+      vol.t_step()=rw.nspacing(4);//T
+    } else {
+      vol.t_start()=0;//T
+      vol.t_step()=0;//T
+    }
+  }
+  
+  template<class T> void save_4d_volume(minc_1_writer& rw,const simple_4d_volume<T>& vol)
+  {
+    if(typeid(T)==typeid(unsigned char))
+      rw.setup_write_byte();
+    else if(typeid(T)==typeid(int))
+      rw.setup_write_int();
+    else if(typeid(T)==typeid(fixed_vec<3,float>))
+      rw.setup_write_float(); 
+    else if(typeid(T)==typeid(float))
+      rw.setup_write_float(); 
+    else if(typeid(T)==typeid(fixed_vec<3,double>))
+      rw.setup_write_double(); 
+    else if(typeid(T)==typeid(double))
+      rw.setup_write_double(); 
+    else 
+			REPORT_ERROR("Data type not supported for minc io"); 
+		
+    std::vector<size_t> strides(MAX_VAR_DIMS,0);
+    size_t str=1;
+    for(size_t i=0;i<4;i++)//T is a special
+    {      
+      if(rw.map_space(i)<0) continue;
+      strides[rw.map_space(i)]=str;
+      str*=rw.ndim(i);
+    }
+    
+    if(rw.map_space(4)>=0)
+      strides[rw.map_space(4)]=0; //t dimension
+    
+    minc_output_iterator<T> out(rw);
+    for(out.begin();!out.last();out.next())
+    {
+      size_t address=0;
+      size_t slice=0;
+      for(size_t i=0;i<rw.dim_no();i++)
+      {
+        if(strides[i]>0)
+          address+=out.cur()[i]*strides[i];
+        else //
+          slice=out.cur()[i];
+      }
+      out.value(vol.frame(slice).c_buf()[address]);
+    }
+  }
+  
+  bool is_same(minc_1_reader& one,minc_1_reader& two,bool verbose=true);
+  
+  template<class T> void load_minc_file(const char *file,simple_4d_volume<T>& vol)
+  {
+      minc_1_reader rdr;
+      rdr.open(file);
+      load_4d_volume(rdr,vol);  
+  }
+  
+  template<class T> void generate_info(const simple_4d_volume<T>& vol,minc_info& info)
+  {
+     bool have_time=vol.frames()>1||vol.t_step()!=0.0; //assume that it is 3D file otherwise
+     
+     bool is_vector=false;
+      
+      if(typeid(T)==typeid(fixed_vec<3,float>)) {
+        is_vector=true;
+      } 
+      
+      info.resize(3+(is_vector?1:0)+(have_time?1:0));
+      
+      if(is_vector)
+      {
+        info[0].dim=dim_info::DIM_VEC;
+        info[0].length=3;
+        info[0].step=1;
+        
+      }
+      
+      for(int i=0;i<3;i++)
+      {
+        int ii=i+(is_vector?1:0);
+        info[ii].dim=dim_info::dimensions( dim_info::DIM_X+i);
+        
+        info[ii].length=vol.dim(i);
+        info[ii].step  =vol.step()[i];
+        info[ii].start =vol.start()[i];
+        info[ii].have_dir_cos=true;
+        
+        for(int j=0;j<3;j++)
+          info[ii].dir_cos[j]=vol.direction_cosines(i)[j];
+      }
+      
+      if(have_time) 
+      {
+        info[3+(is_vector?1:0)].dim=dim_info::DIM_TIME;
+        info[3+(is_vector?1:0)].step=vol.t_step();
+        info[3+(is_vector?1:0)].start=vol.t_start();
+        info[3+(is_vector?1:0)].length=vol.frames();
+      }
+          
+  }
+  
+  template<class T> void save_minc_file(const char *file,const simple_4d_volume<T>& vol,
+                                        const char* history=NULL,const minc_1_reader* original=NULL,
+                                        nc_type datatype=NC_NAT,bool is_signed=false)
+  {
+      minc_1_writer wrt;
+      //convert parameters to info
+      
+      if(typeid(T)==typeid(unsigned char))
+      {
+        if(datatype==NC_NAT) datatype=NC_BYTE;
+        
+      } else if(typeid(T)==typeid(int)) {
+        if(datatype==NC_NAT) datatype=NC_INT;
+        
+        is_signed=true;
+      } else if(typeid(T)==typeid(unsigned int))  {
+        if(datatype==NC_NAT) datatype=NC_INT;
+        
+        is_signed=false;
+      } else if(typeid(T)==typeid(float))  {
+        if(datatype==NC_NAT) datatype=NC_FLOAT;
+        
+        is_signed=true;
+      } else if(typeid(T)==typeid(fixed_vec<3,float>)) {
+        if(datatype==NC_NAT) datatype=NC_FLOAT;
+        
+        is_signed=true;
+      } else if(typeid(T)==typeid(double))  {
+        if(datatype==NC_NAT) datatype=NC_DOUBLE;
+        
+        is_signed=true;
+      } else if(typeid(T)==typeid(fixed_vec<3,double>)) {
+        if(datatype==NC_NAT) datatype=NC_DOUBLE;
+        
+        is_signed=true;
+      } else
+        REPORT_ERROR("Unsupported data type!");
+      
+      minc_info info;
+      generate_info<T>(vol,info);
+      
+      wrt.open(file,info,2,datatype,is_signed);
+      
+      if(original)
+      {
+        wrt.copy_headers(*original);
+      }
+      
+      if(history)
+        wrt.append_history(history);
+      
+      save_4d_volume(wrt,vol);
+  }
+  
+};
+
+#endif //__MINC_1_SIMPLE_RW_H__
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_io_4d_volume.h
@@ -0,0 +1,157 @@
+#ifndef __MINC_IO_4D_VOLUME_H_
+
+#include "minc_io_simple_volume.h"
+#include <vector>
+#include <cstring>
+
+namespace minc
+{
+  
+  //! simple 4D volume - collection of 3D volumes
+  template<class T> class simple_4d_volume
+  {
+    protected:
+      enum    {ndims=3};
+      typedef fixed_vec<ndims,int> idx;
+      typedef fixed_vec<ndims,double> vect;
+      
+      double _start_t;
+      double _step_t;
+      
+      void allocate(int n,const idx& sz)
+      {
+        _volumes.resize(n);
+        for(int i=0;i<n;i++)
+        {
+          _volumes[i].resize(sz);
+        }
+      }
+      
+    public:
+      typedef simple_volume<T> volume;
+      typedef std::vector<volume> volume_list;
+      
+      int dim(int i) const
+      {
+        return _volumes[0].dim(i);
+      }
+      
+      vect voxel_to_world(const idx& iii) const
+      {
+        return _volumes[0].voxel_to_world(iii);
+      }
+      
+      idx world_to_voxel(const vect& iii) const
+      {
+        return _volumes[0].world_to_voxel(iii);
+      }
+      
+      void resize(int x,int y,int z,int t)
+      {
+        allocate(t,IDX<int>(x,y,z));
+      }
+      
+      //! number of temporal frames
+      size_t  frames(void) const
+      {
+        return _volumes.size();
+      }
+      
+      T& at(int x,int y,int z,int t)
+      {
+        return _volumes[t].at(x,y,z);
+      }
+      
+      const T& get(int x,int y,int z,int t) const
+      {
+        return _volumes[t].get(x,y,z);
+      }
+      
+      void set(int x,int y,int z,int t,const T& v)
+      {
+        _volumes[t].set(x,y,z,v);
+      }
+      
+      T& at(const idx& i,int t)
+      {
+        return _volumes[t].at(i);
+      }
+
+      const T& get(const idx& i,int t) const
+      {
+        return _volumes[t].get(i);
+      }
+      
+      void set(const idx& i,int t,const T& v)
+      {
+        _volumes[t].set(i,v);
+      }
+      
+      volume& frame(int t) 
+      {
+        return _volumes[t];
+      }
+
+      const volume& frame(int t) const
+      {
+        return _volumes[t];
+      }
+      
+      vect& start(void)
+      {
+        return _volumes[0].start();
+      }
+      
+      const vect& start(void) const
+      {
+        return _volumes[0].start();
+      }
+      
+      vect& step(void)
+      {
+        return _volumes[0].step();
+      }
+      
+      const vect& step(void) const
+      {
+        return _volumes[0].step();
+      }
+      
+      vect& direction_cosines(int i)
+      {
+        return _volumes[0].direction_cosines(i);
+      }
+      
+      const vect& direction_cosines(int i) const
+      {
+        return _volumes[0].direction_cosines(i);
+      }
+      
+      double & t_step(void)
+      {
+        return _step_t;
+      }
+      
+      double t_step(void) const
+      {
+        return _step_t;
+      }
+      
+      double & t_start(void)
+      {
+        return _start_t;
+      }
+      
+      double t_start(void) const
+      {
+        return _start_t;
+      }
+      
+    protected:
+
+      volume_list _volumes;
+  }; 
+
+};
+
+#endif //__MINC_IO_4D_VOLUME_H_
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_io_exceptions.h
@@ -0,0 +1,58 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : 
+@DESCRIPTION: 
+@COPYRIGHT  :
+              Copyright 2006 Vladimir Fonov, 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 __EXCPETIONS_H__
+#define __EXCPETIONS_H__
+
+#define REPORT_ERROR(MSG) throw minc::generic_error(__FILE__,__LINE__,MSG)
+
+namespace minc
+{
+  class generic_error
+  {
+  public:
+    const char *_file;
+    int _line;
+    const char *_msg;
+    int _code;
+  public:
+
+    generic_error (const char *file, int line, const char *msg = "Error", int code = 0):
+    _file (file), _line (line), _msg (msg), _code (code)
+    {
+      //                    std::cerr<<"Exception created: "<<_file<<":"<<_line<<" "<<_msg<<std::endl;
+    }
+
+    const char *file (void) const
+    {
+      return _file;
+    }
+
+    const char *msg (void) const
+    {
+      return _msg;
+    }
+
+    int line (void) const
+    {
+      return _line;
+    }
+
+    int code (void) const
+    {
+      return _code;
+    }
+  };
+}; //minc
+#endif //__EXCPETIONS_H__
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_io_fixed_vector.h
@@ -0,0 +1,375 @@
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : 
+@DESCRIPTION: 
+@COPYRIGHT  :
+              Copyright 2006 Vladimir Fonov, 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 __FIXED_VECTOR_H__
+#define __FIXED_VECTOR_H__
+
+#include <limits>
+
+namespace minc
+{
+  //! fixed size array, which support arithmetic operations
+  template<int dim,class I=int> class fixed_vec
+  {
+  protected:
+    I c[dim];
+  public:
+    //! default constructor, does nothing (i.e data is uninitilized)
+    fixed_vec() {}
+  
+    //! constructor which sets all the elements to the same value
+    explicit fixed_vec(I v)
+    {
+        for(unsigned int i=0;i<dim;i++)
+            c[i]=v;
+    }
+
+    //! constructor which sets all the elements to be a copy of C-array
+    explicit fixed_vec(const I* v)
+    {
+        for(unsigned int i=0;i<dim;i++)
+            c[i]=v[i];
+    }
+    
+    //! conversion to the C array
+    I* c_buf()
+    {
+      return c;
+    }
+	
+    //! conversion to const C array 
+    const I* c_buf() const
+    {
+      return c;
+    }
+
+    //! element access operator
+    I& operator[](int i)
+    {
+#ifdef _INDEX_CHECK
+      if(i<0 || i>=dim) REPORT_ERROR("Index out of bounds");
+#endif //_INDEX_CHECK
+      return c[i];
+    }
+    //! const element access operator
+    I operator[](int i) const
+    {
+#ifdef _INDEX_CHECK
+      if(i<0 || i>=dim) REPORT_ERROR("Index out of bounds");
+#endif //_INDEX_CHECK
+      return c[i];
+    }
+
+    //! const element access operator
+    I get(int i)
+    {
+      return (*this)[i];
+    }
+    //! element writing operator
+    void set(int i,I v)
+    {
+      (*this)[i]=v;
+    }
+
+    //! find a maximum of elements
+    I max(void) const
+    {
+      I s=std::numeric_limits < I >::min ();;
+      for(unsigned int i=0;i<dim;i++)
+        if(c[i]>s) s=c[i];
+      return s;
+    }
+	
+    //! find a minimum of elements
+    I min(void) const
+    {
+      I s=std::numeric_limits < I >::max ();;
+      for(unsigned int i=0;i<dim;i++)
+        if(c[i]<s) s=c[i];
+      return s;
+    }
+	
+    //! calculate sum of all elements
+    I sum(void) const
+    {
+      I s=0;
+      for(unsigned int i=0;i<dim;i++)
+        s+=c[i];
+      return s;
+    }
+
+    //! modulus squared
+    I mod2(void) const
+    {
+      I s=0;
+      for(unsigned int i=0;i<dim;i++)
+        s+=c[i]*c[i];
+      return s;
+    }
+    
+    //! volume (product of all elements)
+    I vol(void) const
+    {
+      I s=1;
+      for(unsigned int i=0;i<dim;i++)
+        s*=c[i];
+      return s;
+    }
+	
+    //! \name fixed_vec arithmentic operations
+    //@{
+    fixed_vec<dim,I>& operator *=(const fixed_vec<dim,I>& b)
+    {
+      for(unsigned int i=0;i<dim;i++)
+        c[i]*=b[i];
+      return *this;
+    }
+
+    fixed_vec<dim,I>& operator *=(const I b)
+    {
+      for(unsigned int i=0;i<dim;i++)
+        c[i]*=b;
+      return *this;
+    }
+
+    fixed_vec<dim,I>& operator +=(const fixed_vec<dim,I>& b)
+    {
+      for(unsigned int i=0;i<dim;i++)
+        c[i]+=b[i];
+      return *this;
+    }
+
+    fixed_vec<dim,I>& operator -=(const fixed_vec<dim,I>& b)
+    {
+      for(unsigned int i=0;i<dim;i++)
+        c[i]-=b[i];
+      return *this;
+    }
+
+    fixed_vec<dim,I>& operator /=(const fixed_vec<dim,I>& b)
+    {
+      for(unsigned int i=0;i<dim;i++)
+        c[i]/=b[i];
+      return *this;
+    }
+
+    fixed_vec<dim,I>& operator /=(const I b)
+    {
+      for(unsigned int i=0;i<dim;i++)
+        c[i]/=b;
+      return *this;
+    }
+
+    fixed_vec<dim,I> operator /(const I b)
+    {
+      fixed_vec<dim,I> tmp;
+      for(unsigned int i=0;i<dim;i++)
+        tmp[i]=c[i]/b;
+      return tmp;
+    }
+
+    fixed_vec<dim,I> operator *(const I b)
+    {
+      fixed_vec<dim,I> tmp;
+      for(unsigned int i=0;i<dim;i++)
+        tmp[i]=c[i]*b;
+      return tmp;
+    }
+
+    fixed_vec<dim,I> operator -(const fixed_vec<dim,I>& b)
+    {
+      fixed_vec<dim,I> tmp;
+      for(unsigned int i=0;i<dim;i++)
+        tmp[i]=c[i]-b[i];
+      return tmp;
+    }
+
+    fixed_vec<dim,I> operator +(const fixed_vec<dim,I>& b)
+    {
+      fixed_vec<dim,I> tmp;
+      for(unsigned int i=0;i<dim;i++)
+        tmp[i]=c[i]+b[i];
+      return tmp;
+    }
+
+    //@}
+
+    //! assignement operator, copies contents
+    fixed_vec<dim,I>& operator=(const fixed_vec<dim,I>& b)
+    {
+      for(unsigned int i=0;i<dim;i++)
+        c[i]=b[i];
+      return *this;
+    }
+
+    //! assignement operator, copies contents, assumes that b have at least this size
+    fixed_vec<dim,I>& operator=(const I* b)
+    {
+      for(unsigned int i=0;i<dim;i++)
+        c[i]=b[i];
+      return *this;
+    }
+
+    //! assignement operator, sets all elements to the same value
+    fixed_vec<dim,I>& operator=(const I b)
+    {
+      for(unsigned int i=0;i<dim;i++) c[i]=b;
+      return *this;
+    }
+
+    //! inequality operator, does element wise equality check
+    bool operator!=(const fixed_vec<dim,I>& b) const
+    {
+      for(int i=0;i<dim;i++) if(c[i]!=b[i]) return true;
+      return false;
+    }
+	
+    //! equality operator, does element wise equality check
+    bool operator==(const fixed_vec<dim,I>& b) const
+    {
+      for(int i=0;i<dim;i++) if(c[i]!=b[i]) return false;
+      return true;
+    }
+    
+    //! reverse the order of elements
+    void reverse(void)
+    {
+      for(int i=0;i<dim/2;i++)
+      {
+        I tmp=c[i];
+        c[i]=c[dim-i-1];
+        c[dim-i-1]=tmp;
+      }
+    }
+  };
+
+  //! element wise division
+	template<int dim,class I> fixed_vec<dim,I> operator/(const fixed_vec<dim,I> &l,const fixed_vec<dim,I> &r)
+	{
+		fixed_vec<dim,I> out=l;
+		out/=r;
+		return out; //this is not effecient  - no return value optimisation
+	}
+  
+	//! element wise multiplication
+	template<int dim,class I> fixed_vec<dim,I> operator*(const fixed_vec<dim,I> &l,const fixed_vec<dim,I> &r)
+	{
+		fixed_vec<dim,I> out=l;
+		out*=r;
+		return out; //this is not effecient  - no return value optimisation
+	}
+  
+	//! element wise addition
+	template<int dim,class I> fixed_vec<dim,I> operator+(const fixed_vec<dim,I> &l,const fixed_vec<dim,I> &r)
+	{
+		fixed_vec<dim,I> out=l;
+		out+=r;
+		return out; //this is not effecient  - no return value optimisation
+	}
+	
+  //! element wise subtraction
+	template<int dim,class I> fixed_vec<dim,I> operator-(const fixed_vec<dim,I> &l,const fixed_vec<dim,I> &r)
+	{
+		fixed_vec<dim,I> out=l;
+		out-=r;
+		return out; //this is not effecient  - no return value optimisation
+	}
+	
+	//! devide all elements by a value
+	template<int dim,class I> fixed_vec<dim,I> operator/(const fixed_vec<dim,I> &l,I r)
+	{
+		fixed_vec<dim,I> out=l;
+		out/=r;
+		return out; //this is not effecient  - no return value optimisation
+	}
+	
+  //! multiply all elements by a value 
+	template<int dim,class I> fixed_vec<dim,I> operator*(const fixed_vec<dim,I> &l,I r)
+	{
+		fixed_vec<dim,I> out=l;
+		out*=r;
+		return out; //this is not effecient  - no return value optimisation
+	}
+	
+  //! add a value to all elements 
+	template<int dim,class I> fixed_vec<dim,I> operator+(const fixed_vec<dim,I> &l,I r)
+	{
+		fixed_vec<dim,I> out=l;
+		out+=r;
+		return out; //this is not effecient  - no return value optimisation
+	}
+	
+  //! subtract a value from all elements 
+	template<int dim,class I> fixed_vec<dim,I> operator-(const fixed_vec<dim,I> &l,I r)
+	{
+		fixed_vec<dim,I> out=l;
+		out-=r;
+		return out; //this is not effecient  - no return value optimisation
+	}
+	
+	//! create 1d fixed_vec
+	template<class I> fixed_vec<1,I> IDX(I i)
+	{
+		fixed_vec<1,I> d;
+		d[0]=i;
+		return d;
+	}
+	
+	//! create 2d fixed_vec
+	template<class I> fixed_vec<2,I> IDX(I i,I j)
+	{
+		fixed_vec<2,I> d;
+		d[0]=i;
+		d[1]=j;
+		return d;
+	}
+	
+	//! create 3d fixed_vec
+	template<class I> fixed_vec<3,I> IDX(I i,I j,I k)
+	{
+		fixed_vec<3,I> d;
+		d[0]=i;
+		d[1]=j;
+		d[2]=k;
+		return d;
+	}
+	
+	//! create 4d fixed_vec
+	template<class I> fixed_vec<4,I> IDX(I i,I j,I k,I l)
+	{
+		fixed_vec<3,I> d;
+		d[0]=i;
+		d[1]=j;
+		d[2]=k;
+		d[3]=l;
+		return d;
+	}
+	
+	//!average value of a vector
+	template<class T,int d>T AVG(const fixed_vec<d,T> &v)
+	{
+		return v.sum()/d;
+	}	
+  
+	//!dot product of two vectors
+  template<class T,int d>T dot(const fixed_vec<d,T> &v1,const fixed_vec<d,T> &v2)
+  {
+    T val=0;
+    for(int i=0;i<d;i++) val+=v1[i]*v2[i];
+    return val;
+  }	
+	
+};
+
+#endif //__FIXED_VECTOR_H__
new file mode 100644
--- /dev/null
+++ b/ezminc/minc_io_simple_volume.h
@@ -0,0 +1,554 @@
+#ifndef __SIMPLE_VOLUME_H__
+#define __SIMPLE_VOLUME_H__
+
+#include "minc_io_exceptions.h"
+#include "minc_io_fixed_vector.h"
+#include <string.h>
+#include <math.h>
+
+namespace minc 
+{
+  //! very simple 3D volume, initially created as an example but became usable
+    template<class T> class simple_volume
+    {
+    public:
+    
+      enum    {ndims=3};
+      typedef fixed_vec<ndims,int> idx;
+      typedef fixed_vec<ndims,double> vect;
+      
+    protected:
+    
+      T * _vol;    //! the volume itself
+      idx _size;   //! dimension sizes
+      idx _stride; //! used internally 
+      int _count;  //! total number of voxels
+      bool _free_memory; //! should the array be freed
+      
+      vect _step,_start;    //! conversion to wold coordinates
+      vect _direction_cosines[3];
+      
+      
+      void _allocate(T* data=NULL)
+      {
+        _stride[0]=1;
+        int total=_size[0];
+        for(int i=1;i<ndims;i++)
+        {
+          _stride[i]=_size[i-1]*_stride[i-1];
+          total*=_size[i];
+        }
+        _count=total;
+        if(data)
+        {
+          _vol=data;
+          _free_memory=false;
+        } else {
+          _vol=new T[total];
+          _free_memory=true;
+        }
+        
+        _step=IDX<double>(1.0,1.0,1.0);
+        _start=IDX<double>(0.0,0.0,0.0);
+        
+        _direction_cosines[0]=IDX<double>(1.0,0.0,0.0);
+        _direction_cosines[1]=IDX<double>(0.0,1.0,0.0);
+        _direction_cosines[2]=IDX<double>(0.0,0.0,1.0);
+        
+      }
+
+    public:
+      vect& start(void)
+      {
+        return _start;
+      }
+      
+      const vect& start(void) const
+      {
+        return _start;
+      }
+
+      vect& step(void)
+      {
+        return _step;
+      }
+      
+      
+      const vect& step(void) const
+      {
+        return _step;
+      }
+      
+      vect& direction_cosines(int i)
+      {
+        return _direction_cosines[i];
+      }
+      
+      const vect& direction_cosines(int i) const
+      {
+        return _direction_cosines[i];
+      }
+
+      operator T*() 
+      {
+        return _vol;
+      }
+      
+      T* c_buf() 
+      {
+        return _vol;
+      }
+      
+      const T* c_buf() const
+      {
+        return _vol;
+      }
+      
+      int c_buf_size() const
+      {
+        return _count;
+      }
+
+      explicit simple_volume(const int* dims):_vol(0),_size(dims)
+      {
+        _allocate();
+      }
+      
+      simple_volume(const simple_volume<T>& a,bool copy_data=true):_vol(0)
+      {
+        for(int i=0;i<ndims;i++) 
+          _size[i]=a._size[i];
+        _allocate();
+        
+        if(copy_data)
+        {
+          memmove(_vol,a._vol,_size[0]*_size[1]*_size[2]*sizeof(T));
+        }
+        
+        _step=a._step;
+        _start=a._start;
+        for(int i=0;i<ndims;i++)
+          _direction_cosines[i]=a._direction_cosines[i];
+      }
+      
+      simple_volume(int sx,int sy,int sz):_vol(0)
+      {
+        _size=IDX(sx,sy,sz);
+        _allocate();
+      }
+      
+      explicit simple_volume(const idx& s):_vol(0)
+      {
+        _size=s;
+        _allocate();
+      }
+
+      simple_volume():_vol(0)
+      {
+        for(int i=0;i<ndims;i++)
+        {
+          _size[i]=0;
+          _step[i]=0.0;
+          _start[i]=0.0;
+          
+          _direction_cosines[i]=IDX<double>(0.0,0.0,0.0);
+          _direction_cosines[i][i]=1.0;
+        }
+      }
+      
+      bool empty(void) const
+      {
+        return !_size[0]||!_vol;
+      }
+      
+      void resize(int sx,int sy,int sz)
+      {
+        if( _size[0]==sx && _size[1]==sy && _size[2]==sz )
+          return;
+        
+        if(_vol && _free_memory)
+          delete [] _vol;
+        _size=IDX(sx,sy,sz);
+        _allocate();
+      }
+      
+      void resize(const idx& s)
+      {
+        if(_size==s) return;
+        
+        if(_vol&&_free_memory)
+          delete [] _vol;
+        _size=s;
+        _allocate();
+      }
+      
+      virtual ~simple_volume()
+      {
+        if(_vol && _free_memory)
+          delete [] _vol;
+      }
+      
+      T& operator()(int x,int y,int z)
+      {
+        return _vol[x+y*_stride[1]+z*_stride[2]];
+      }
+      
+      T& operator()(const idx& i)
+      {
+        return _vol[dot(i,_stride)];
+      }
+      
+      const T& operator()(int x,int y,int z) const
+      {
+        return get(x,y,z);
+      }
+      
+      const T& operator()(const idx& i) const
+      {
+        return get(i);
+      }
+      
+      const T& get(int x,int y,int z) const
+      {
+        return _vol[x+y*_stride[1]+z*_stride[2]];
+      }
+      
+      const T& get(const idx& i) const
+      {
+        return _vol[dot(i,_stride)];
+      }
+      
+      const T& safe_get(int x,int y,int z) const
+      {
+        check_index(x,y,z);
+        return _vol[x+y*_stride[1]+z*_stride[2]];
+      }
+     
+      const T& safe_get(idx i) const
+      {
+        check_index(i);
+        return get(i);
+      }
+
+      //trilinear intrpolation
+      double interpolate(float _x,float _y,float _z) const
+      {
+        int x=floor(_x);
+        int y=floor(_y);
+        int z=floor(_z);
+        
+        float dx=_x-x;
+        float dy=_y-y;
+        float dz=_z-z;
+        
+        if(x<0) x=-x;
+        if(y<0) y=-y;
+        if(z<0) z=-z;
+        
+        if(x>=(_size[0]-1)) x=_size[0]*2-3-x;
+        if(y>=(_size[1]-1)) y=_size[1]*2-3-y;
+        if(z>=(_size[2]-1)) z=_size[2]*2-3-z;
+        
+        //trilinear intrpolation
+        return     (1.0-dx)*(1.0-dy)*(1.0-dz)*get(x,y,z)+
+        
+                   dx*(1.0-dy)*(1.0-dz)*get(x+1,y,z)+
+                   (1.0-dx)*dy*(1.0-dz)*get(x,y+1,z)+
+                   (1.0-dx)*(1.0-dy)*dz*get(x,y,z+1)+
+                   
+                   dx*(1.0-dy)*dz*get(x+1,y,z+1)+
+                   (1.0-dx)*dy*dz*get(x,y+1,z+1)+
+                   dx*dy*(1.0-dz)*get(x+1,y+1,z)+
+                   
+                   dx*dy*dz*get(x+1,y+1,z+1);
+      }
+      
+      T set(int x,int y,int z, const T&v)
+      {
+        return _vol[x+y*_stride[1]+z*_stride[2]]=v;
+      }
+      
+      T set(const idx& i, const T&v)
+      {
+        return _vol[dot(i,_stride)]=v;
+      }
+      
+      int dim(int i) const
+      {
+        return _size[i];
+      }
+      
+      const int* dims() const
+      {
+        return _size.c_buf();
+      }
+      
+      const idx& size() const
+      {
+        return _size;
+      }
+      
+      void extract_subvolume(simple_volume<T>& dst,const idx& s, const idx& f) const
+      {
+        for(int k=s[2];k<f[2];k++)
+         for(int j=s[1];j<f[1];j++)
+          for(int i=s[0];i<f[0];i++)
+            dst(i,j,k)=get(i,j,k);
+      }
+      
+      void check_index(int &ii,int &jj,int &kk) const
+      {
+        if(ii<0) ii=-ii;
+        if(jj<0) jj=-jj;
+        if(kk<0) kk=-kk;
+
+        if(ii>=dim(0)) ii=2*dim(0)-ii-1;
+        if(jj>=dim(1)) jj=2*dim(1)-jj-1;
+        if(kk>=dim(2)) kk=2*dim(2)-kk-1;
+      }
+      
+      void check_index(idx& iii)
+      {
+        for(int i=0;i<3;i++)
+        {
+          if(iii[i]<0) 
+            iii[i]=-iii[i];
+
+          if(iii[i]>=dim(i)) 
+            iii[i]=2*dim(i)-iii[i]-1;
+
+        }
+      }
+
+      bool hit(int ii,int jj,int kk) const
+      {
+        if(ii<0) return false;
+        if(jj<0) return false;
+        if(kk<0) return false;
+
+        if(ii>=dim(0)) return false;
+        if(jj>=dim(1)) return false;
+        if(kk>=dim(2)) return false;
+        return true;
+      }
+      
+      bool hit(const idx iii) const
+      {
+        for(int i=0;i<3;i++)
+        {
+          if(iii[i]<0) return false;
+          if(iii[i]>=dim(i)) return false;
+        }
+        return true;
+      }
+          
+      simple_volume<T>& operator+=(const simple_volume<T>& a)
+      {
+        for(int i=0;i<ndims;i++) 
+          if(_size[i]!=a._size[i])
+            REPORT_ERROR("Dimensions are different");
+        
+        for(int i=0;i<_count;i++)
+          _vol[i]+=a._vol[i];
+        return *this;
+      }
+      
+      simple_volume<T>& operator+=(const T& a)
+      {
+        for(int i=0;i<_count;i++)
+          _vol[i]+=a;
+        return *this;
+      }
+      
+      simple_volume<T>& operator-=(const simple_volume<T>& a)
+      {
+         if(_size!=a._size)
+            REPORT_ERROR("Dimensions are different");
+        
+        for(int i=0;i<_count;i++)
+          _vol[i]-=a._vol[i];
+        return *this;
+      }
+      
+      simple_volume<T>& operator-=(const T& a)
+      {
+        for(int i=0;i<_count;i++)
+          _vol[i]-=a;
+        return *this;
+      }
+      
+      simple_volume<T>& operator*=(const simple_volume<T>& a)
+      {
+        for(int i=0;i<ndims;i++) 
+          if(_size[i]!=a._size[i])
+            REPORT_ERROR("Dimensions are different");
+        
+        for(int i=0;i<_count;i++)
+          _vol[i]*=a._vol[i];
+        return *this;
+      }
+      
+      simple_volume<T>& operator*=(const T& a)
+      {
+        for(int i=0;i<_count;i++)
+          _vol[i]*=a;
+        return *this;
+      }
+      
+      simple_volume<T>& operator/=(const simple_volume<T>& a)
+      {
+        if(_size!=a._size())
+          REPORT_ERROR("Dimensions are different");
+        
+        for(int i=0;i<_count;i++)
+          _vol[i]/=a._vol[i];
+        return *this;
+      }
+      
+      simple_volume<T>& operator/=(const T& a)
+      {
+        for(int i=0;i<_count;i++)
+          _vol[i]/=a;
+        return *this;
+      }
+      
+      simple_volume& operator=(const simple_volume<T>&a)
+      {
+        resize(a.dim(0),a.dim(1),a.dim(2));
+        
+        memmove(_vol, a._vol, _count*sizeof(T));
+        
+        _step=a._step;
+        _start=a._start;
+        
+        for(int i=0;i<ndims;i++)
+          _direction_cosines[i]=a._direction_cosines[i];
+        
+        return *this;
+      }
+      
+      simple_volume& operator=(const T&a)
+      {
+        for(int i=0;i<_count;i++)
+          _vol[i]=a;
+        return *this;
+      }
+      
+      void weighted_add(const simple_volume<T>&a, double w)
+      {
+        if(_size!=a._size)
+          REPORT_ERROR("Dimensions are different");
+        
+        for(int i=0;i<_count;i++)
+          _vol[i]+=a._vol[i]*w;
+      }
+      
+      vect voxel_to_world(const idx& iii) const
+      {
+        vect ret=IDX<double>(0.0,0.0,0.0);
+        for(int i=0;i<ndims;i++)
+        {
+          for(int j=0;j<ndims;j++)
+            ret[i]+=(_step[j]*iii[j]+_start[j])*_direction_cosines[j][i];
+        }
+        return ret;
+      }
+
+      vect world_to_voxel_c(const vect& iii) const
+      {
+        vect ret=IDX<double>(0.0,0.0,0.0);
+        for(int i=0;i<ndims;i++)
+        {
+          for(int j=0;j<ndims;j++)
+            ret[i]+=((iii[j]-_start[j])/_step[j])*_direction_cosines[i][j]; //transpose!
+        }
+        return ret;
+      }
+
+      idx world_to_voxel(const vect& iii) const
+      {
+        vect ret=world_to_voxel_c(iii);
+        
+        idx r;
+        
+        for(int i=0;i<ndims;i++)
+          r[i]=floor(ret[i]+0.5);
+        
+        return r;
+      }
+      
+      //!use provided buffer for storage
+      void assign(const idx& s,T* array) 
+      {
+        _size=s;
+        allocate(array);
+      }
+      
+  };
+  
+  //! remove (unpad) or add padding as needed, volume will be centered
+  template<class T>void pad_volume(const simple_volume<T> &src,simple_volume<T> &dst, const T& fill)
+  {
+    fixed_vec<3,int> sz1=src.size();
+    fixed_vec<3,int> sz2=dst.size();
+    fixed_vec<3,int> d=sz2-sz1;
+    fixed_vec<3,int> i;
+    
+    d/=2;//offset
+  
+    for( i[2]=0;i[2]<sz2[2];i[2]++)
+      for( i[1]=0;i[1]<sz2[1];i[1]++)
+        for( i[0]=0;i[0]<sz2[0];i[0]++)
+    {
+      fixed_vec<3,int> j= i-d;
+      
+      if( src.hit(j)) 
+        dst.set(i,src.get(j));
+      else
+        dst.set(i,fill);
+    }
+  }
+  
+  template<class T>void volume_min_max(const simple_volume<T>& v,T &_min,T &_max)
+  {
+    _min=_max=v.c_buf()[0];
+    
+    for(int i=0;i<v.c_buf_size();i++)
+    {
+			if(isnan(v.c_buf()[i]) || isinf(v.c_buf()[i])) 
+				continue;
+			
+      if(v.c_buf()[i]>_max) _max=v.c_buf()[i];
+      else if(v.c_buf()[i]<_min) _min=v.c_buf()[i];
+    }
+  }
+  
+  template<class T> void  volume_min_max(const simple_volume<T>& v,const simple_volume<unsigned char>& mask,T &_min,T &_max)
+  {
+    if(v.size()!=mask.size())
+      REPORT_ERROR("Volume size mismatch");
+    
+    _min=1e10;
+    _max=-1e10;
+    
+    for(int i=0;i<v.c_buf_size();i++)
+    {
+      if(mask.c_buf()[i])
+      {
+				if(isnan(v.c_buf()[i]) || isinf(v.c_buf()[i])) 
+					continue;
+        if(v.c_buf()[i]>_max) _max=v.c_buf()[i];
+        else if(v.c_buf()[i]<_min) _min=v.c_buf()[i];
+      }
+    }
+  }
+  
+  
+  typedef simple_volume<float>               minc_float_volume;
+  typedef simple_volume<fixed_vec<3,float> > minc_grid_volume;
+  typedef simple_volume<unsigned char>       minc_byte_volume;
+
+}; //minc
+
+
+#endif // __SIMPLE_VOLUME_H__