Mercurial > hg > minc-tools
changeset 2564:f99952fb216f
Merge remote branch 'origin/master'
author | Andrew L Janke <a.janke@gmail.com> |
---|---|
date | Wed, 22 Feb 2012 00:55:50 +1000 |
parents | 4b26fb8b776c (current diff) 73b8c991cf38 (diff) |
children | 9a32f1651a9c |
files | Makefile.am progs/minccalc/y.tab.h |
diffstat | 58 files changed, 9345 insertions(+), 955 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,8 +16,8 @@ # Packaging defines SET(CPACK_GENERATOR TGZ) SET(CPACK_PACKAGE_VERSION_MAJOR 2) -SET(CPACK_PACKAGE_VERSION_MINOR 0) -SET(CPACK_PACKAGE_VERSION_PATCH 17) +SET(CPACK_PACKAGE_VERSION_MINOR 1) +SET(CPACK_PACKAGE_VERSION_PATCH 1) INCLUDE(CPack) @@ -28,20 +28,20 @@ SET(PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") +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) +IF(BUILD_EZMINC) +OPTION(BUILD_MINC4ITK "Build ITK interface" ON) +ENDIF(BUILD_EZMINC) -# yes, build as minc2 -SET(MINC2 "1") + ADD_DEFINITIONS(-DHAVE_CONFIG_H) # aliases SET(VERSION "${PACKAGE_VERSION}") -# progs needed to build -#SET(FLEX_FIND_REQUIRED) -#SET(BISON_FIND_REQUIRED) -#FIND_PACKAGE(BISON) -#FIND_PACKAGE(FLEX) - # check for prereqs INCLUDE(CheckFunctionExists) @@ -52,11 +52,15 @@ CHECK_INCLUDE_FILES(float.h HAVE_FLOAT_H) # netcdf and HDF5 -SET(NETCDF_FIND_REQUIRED TRUE) -SET(HDF5_FIND_REQUIRED TRUE) -FIND_PACKAGE(HDF5) -FIND_PACKAGE(NETCDF) -INCLUDE_DIRECTORIES( ${NETCDF_INCLUDE_DIR} ${HDF5_INCLUDE_DIR} ) +FIND_PACKAGE(NETCDF REQUIRED) +INCLUDE_DIRECTORIES( ${NETCDF_INCLUDE_DIR} ) + +IF(BUILD_MINC2) + FIND_PACKAGE(HDF5 REQUIRED) + FIND_PACKAGE(ZLIB REQUIRED) + SET(MINC2 "1") + INCLUDE_DIRECTORIES( ${HDF5_INCLUDE_DIR} ) +ENDIF(BUILD_MINC2) # config files for build CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake ${CMAKE_SOURCE_DIR}/config.h) @@ -68,10 +72,16 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/libsrc - ${CMAKE_SOURCE_DIR}/libsrc2 ${CMAKE_SOURCE_DIR}/volume_io/Include ) +IF(BUILD_MINC2) + INCLUDE_DIRECTORIES( + ${CMAKE_SOURCE_DIR}/libsrc2 + ) +ENDIF(BUILD_MINC2) + + # some variables SET(minc1_LIB_SRCS libsrc/ParseArgv.c @@ -105,26 +115,56 @@ libsrc2/volume.c ) +SET(minc_LIB minc) + +IF(BUILD_MINC2) + SET(minc_LIB_SRCS ${minc1_LIB_SRCS} ${minc2_LIB_SRCS}) + SET(minc_LIB minc2) + ADD_LIBRARY(minc2 STATIC ${minc_LIB_SRCS} ) + + TARGET_LINK_LIBRARIES(minc2 ${NETCDF_LIBRARY} ${HDF5_LIBRARY} ${ZLIB_LIBRARIES} m ) + + INSTALL(TARGETS minc2 ARCHIVE DESTINATION lib) + + INSTALL(FILES libsrc/minc.h libsrc/ParseArgv.h + libsrc/voxel_loop.h + libsrc/nd_loop.h + libsrc/time_stamp.h + libsrc/minc_compat.h + volume_io/Include/volume_io.h + libsrc2/minc2.h + libsrc/minc_simple.h + DESTINATION include + ) + + SET_TARGET_PROPERTIES(minc2 PROPERTIES VERSION ${PACKAGE_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) + +ELSE(BUILD_MINC2) + + SET(minc_LIB_SRCS ${minc1_LIB_SRCS} ) + SET(minc_LIB minc) + ADD_LIBRARY(minc STATIC ${minc1_LIB_SRCS} ) + TARGET_LINK_LIBRARIES(minc ${NETCDF_LIBRARY} ) + INSTALL(TARGETS minc ARCHIVE DESTINATION lib) + + INSTALL(FILES libsrc/minc.h libsrc/ParseArgv.h + libsrc/voxel_loop.h + libsrc/nd_loop.h + libsrc/time_stamp.h + libsrc/minc_compat.h + volume_io/Include/volume_io.h + libsrc/minc_simple.h + DESTINATION include + ) + + SET_TARGET_PROPERTIES(minc PROPERTIES VERSION ${PACKAGE_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) + +ENDIF(BUILD_MINC2) # build the main minc2 library -ADD_LIBRARY(minc2 STATIC ${minc1_LIB_SRCS} ${minc2_LIB_SRCS}) -INSTALL(TARGETS minc2 DESTINATION lib) -INSTALL(FILES libsrc/minc.h libsrc/ParseArgv.h - libsrc/voxel_loop.h - libsrc/nd_loop.h - libsrc/time_stamp.h - libsrc/minc_compat.h - volume_io/Include/volume_io.h - libsrc2/minc2.h - libsrc/minc_simple.h - DESTINATION include - ) - -SET_TARGET_PROPERTIES(minc2 PROPERTIES VERSION ${PACKAGE_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) - # volume_io2 -SET(volume_io2_LIB_SRCS +SET(volume_io_LIB_SRCS volume_io/Geometry/colour.c volume_io/Geometry/colour_def.c volume_io/Geometry/gaussian.c @@ -161,9 +201,20 @@ volume_io/Volumes/volumes.c ) -# build and install volume_io2 library -ADD_LIBRARY(volume_io2 STATIC ${volume_io2_LIB_SRCS}) -INSTALL(TARGETS volume_io2 DESTINATION lib) +IF(BUILD_MINC2) + # build and install volume_io2 library + ADD_LIBRARY(volume_io2 STATIC ${volume_io_LIB_SRCS}) + INSTALL(TARGETS volume_io2 ARCHIVE DESTINATION lib) + SET_TARGET_PROPERTIES(volume_io2 PROPERTIES VERSION ${PACKAGE_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) + SET( volume_io_LIB volume_io2) + +ELSE(BUILD_MINC2) + ADD_LIBRARY(volume_io STATIC ${volume_io_LIB_SRCS}) + INSTALL(TARGETS volume_io ARCHIVE DESTINATION lib) + SET_TARGET_PROPERTIES(volume_io PROPERTIES VERSION ${PACKAGE_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) + SET( volume_io_LIB volume_io) +ENDIF(BUILD_MINC2) + INSTALL(FILES volume_io/Include/volume_io/alloc.h volume_io/Include/volume_io/arrays.h volume_io/Include/volume_io/basic.h @@ -182,13 +233,20 @@ volume_io/Include/volume_io/volume_cache.h DESTINATION include/volume_io) -SET_TARGET_PROPERTIES(volume_io2 PROPERTIES VERSION ${PACKAGE_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) - - +IF(BUILD_TOOLS) # now build the progs subdir ADD_SUBDIRECTORY( progs ) +ENDIF(BUILD_TOOLS) - +IF(BUILD_CONVERTERS) # and then the conversion subdir ADD_SUBDIRECTORY( conversion ) +ENDIF(BUILD_CONVERTERS) +IF(BUILD_EZMINC) +ADD_SUBDIRECTORY( ezminc ) +ENDIF(BUILD_EZMINC) + +IF(BUILD_MINC4ITK AND BUILD_EZMINC) +ADD_SUBDIRECTORY( minc4itk ) +ENDIF(BUILD_MINC4ITK AND BUILD_EZMINC) \ No newline at end of file
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2011-12-20 Andrew L Janke <a.janke@gmail.com> + * libsrc/netcdf_convenience.c: changed execute_decompress_command() + to always decompress the whole file as the approach used for + netCDF files for header_only does not work with HDF5 MINC2 files + * merged Vlad's ezminc branch + +2011-06-29 Andrew L Janke <a.janke@gmail.com> + * configure.in: changed typo from enable to disable minc2 + +2011-05-30 Andrew L Janke <a.janke@gmail.com> + * progs/minccalc: added imax() and imin() operators 2011-04-29 Andrew L Janke <a.janke@gmail.com> * libsrc2/volume.c: added minc_version global
--- a/Makefile.am +++ b/Makefile.am @@ -82,7 +82,7 @@ progs/Proglib/minc_def.h \ progs/minccalc/errx.h \ progs/minccalc/node.h \ - progs/minccalc/y.tab.h \ + progs/minccalc/gram.h \ progs/mincresample/mincresample.h \ progs/mincreshape/mincreshape.h \ libsrc2/minc2_private.h \
--- a/configure.in +++ b/configure.in @@ -16,7 +16,6 @@ AM_PROG_CC_C_O AC_PROG_F77 AM_PROG_LEX -AM_PROG_LEX AC_PROG_YACC AC_HEADER_TIME @@ -42,7 +41,7 @@ mni_REQUIRE_LIB(m,[#include <math.h>],[double x = sqrt(3.);]) mni_REQUIRE_LIB(netcdf,[#include <netcdf.h>],[int i = ncopen("",0);]) AC_ARG_ENABLE(disminc2, - [ --disable-minc2 enable HDF5 (MINC 2) functionality], + [ --disable-minc2 disable HDF5 (MINC 2) functionality], [ case "${disableval}" in yes) disminc2=true ;; no) disminc2=false ;;
--- a/conversion/CMakeLists.txt +++ b/conversion/CMakeLists.txt @@ -2,8 +2,13 @@ # # Andrew Janke - a.janke@gmail.com -LINK_DIRECTORIES(../) -LINK_LIBRARIES( minc2 ${NETCDF_LIBRARY} ${HDF5_LIBRARY} ) +#LINK_DIRECTORIES() +IF(BUILD_MINC2) + LINK_LIBRARIES( minc2 ${NETCDF_LIBRARY} ${HDF5_LIBRARY} ) +ELSE(BUILD_MINC2) + LINK_LIBRARIES( minc ${NETCDF_LIBRARY} ) +ENDIF(BUILD_MINC2) + ADD_DEFINITIONS(-DHAVE_CONFIG_H) @@ -19,9 +24,8 @@ Acr_nema/group.c Acr_nema/message.c Acr_nema/value_repr.c) -#INSTALL(TARGETS acr_nema DESTINATION lib) -ADD_EXECUTABLE(../dcm2mnc +ADD_EXECUTABLE(dcm2mnc dcm2mnc/dcm2mnc.c dcm2mnc/dicom_to_minc.c dcm2mnc/siemens_to_dicom.c @@ -29,49 +33,60 @@ dcm2mnc/minc_file.c dcm2mnc/progress.c dcm2mnc/string_to_filename.c) -TARGET_LINK_LIBRARIES(../dcm2mnc acr_nema ) +TARGET_LINK_LIBRARIES(dcm2mnc acr_nema ) -ADD_EXECUTABLE(../ecattominc +ADD_EXECUTABLE(ecattominc ecattominc/ecattominc.c ecattominc/insertblood.c ecattominc/ecat_file.c ecattominc/machine_indep.c ) -ADD_EXECUTABLE(../minctoecat +ADD_EXECUTABLE(minctoecat minctoecat/minctoecat.c minctoecat/ecat_write.c minctoecat/machine_indep.c ) -TARGET_LINK_LIBRARIES(../minctoecat volume_io2 minc2) -ADD_EXECUTABLE(../mnc2nii +IF(BUILD_MINC2) + TARGET_LINK_LIBRARIES(minctoecat volume_io2 minc2) +ELSE(BUILD_MINC2) + TARGET_LINK_LIBRARIES(minctoecat volume_io minc) +ENDIF(BUILD_MINC2) + + +ADD_EXECUTABLE(mnc2nii nifti1/mnc2nii.c nifti1/nifti1_io.c nifti1/znzlib.c ) -ADD_EXECUTABLE(../nii2mnc +ADD_EXECUTABLE(nii2mnc nifti1/nii2mnc.c nifti1/nifti1_io.c nifti1/znzlib.c ) -TARGET_LINK_LIBRARIES(../nii2mnc volume_io2 minc2) -ADD_EXECUTABLE(../upet2mnc +IF(BUILD_MINC2) + TARGET_LINK_LIBRARIES(nii2mnc volume_io2 minc2) +ELSE(BUILD_MINC2) + TARGET_LINK_LIBRARIES(nii2mnc volume_io minc) +ENDIF(BUILD_MINC2) + +ADD_EXECUTABLE(upet2mnc micropet/upet2mnc.c ) -ADD_EXECUTABLE(../vff2mnc +ADD_EXECUTABLE(vff2mnc vff2mnc/vff2mnc.c ) # install progs INSTALL(TARGETS - ../dcm2mnc - ../ecattominc - ../minctoecat - ../mnc2nii - ../nii2mnc - ../upet2mnc - ../vff2mnc + dcm2mnc + ecattominc + minctoecat + mnc2nii + nii2mnc + upet2mnc + vff2mnc DESTINATION bin)
--- a/conversion/minctoecat/machine_indep.c +++ b/conversion/minctoecat/machine_indep.c @@ -61,7 +61,7 @@ } #if defined(__alpha) || defined(_WIN32) /* LITTLE_ENDIAN : alpha, intel */ -ftovaxf(f, bufr) +void ftovaxf(f, bufr) float f; unsigned short *bufr; { @@ -84,7 +84,7 @@ bufr[1] = ret >>16; } #else /* BIG ENDIAN : sun hp sgi*/ -ftovaxf(orig,number) +void ftovaxf(orig,number) unsigned short number[2]; float orig; {
new file mode 100644 --- /dev/null +++ b/ezminc/CMakeLists.txt @@ -0,0 +1,35 @@ +OPTION(BUILD_EZMINC_EXAMPLES "Build EZminc examples" ON) + + + +IF(BUILD_MINC2) + ADD_DEFINITIONS( -DMINC2 ) +ENDIF(BUILD_MINC2) + + +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}) +TARGET_LINK_LIBRARIES(minc_io ${minc_LIB}) + +INSTALL(TARGETS minc_io ARCHIVE DESTINATION lib) +INSTALL(FILES ${MINC_IO_HEADERS} DESTINATION include) + + +IF(BUILD_EZMINC_EXAMPLES) +ADD_SUBDIRECTORY(examples) +ENDIF(BUILD_EZMINC_EXAMPLES) \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/ezminc/examples/CMakeLists.txt @@ -0,0 +1,13 @@ +LINK_LIBRARIES( minc_io ) + +ADD_EXECUTABLE(fuzzy_volume_similarity fuzzy_volume_similarity.cpp) +ADD_EXECUTABLE(trilinear_resample trilinear_resample.cpp) +ADD_EXECUTABLE(volume_avg volume_avg.cpp) +ADD_EXECUTABLE(volume_msq_dist volume_msq_dist.cpp) +ADD_EXECUTABLE(volume_similarity volume_similarity.cpp) + +INSTALL(TARGETS + fuzzy_volume_similarity + volume_similarity + DESTINATION bin) +
new file mode 100644 --- /dev/null +++ b/ezminc/examples/fuzzy_volume_similarity.cpp @@ -0,0 +1,209 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : fuzzy_volume_similarity +@DESCRIPTION: an example of implimentation of fuzzy volume similarity +@COPYRIGHT : + Copyright 2011 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 "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" +#include <getopt.h> +#include <algorithm> + +using namespace minc; + +void show_usage (const char * prog) +{ + std::cout<<"Program calculates fuzzy volume similarity metrics"<<std::endl + <<"based on : William R. Crum, Oscar Camara, and Derek L. G. Hill" + <<"\"Generalized Overlap Measures for Evaluation and Validation in Medical Image Analysis \"" + <<" IEEE TRANSACTIONS ON MEDICAL IMAGING, VOL. 25, NO. 11, NOVEMBER 2006"<<std::endl + <<"http://dx.doi.org/10.1109/TMI.2006.880587"<<std::endl<<std::endl + <<"Usage: "<<prog<<" <input1.mnc> <input2.mnc> [--verbose --mask <mask.mnc>]"<<std::endl; + +} + +template<class T>class find_min_max +{ + public: + T _min; + T _max; + bool _initialized; + int _count; + + find_min_max():_initialized(false),_min(0),_max(0),_count(0) + { + } + + void operator()(const T& v) + { + if(_initialized) + { + if(v<_min) _min=v; + if(v>_max) _max=v; + } else { + _initialized=true; + _min=v; + _max=v; + } + _count++; + } + + const T& min(void) const { + return _min; + } + + const T& max(void) const{ + return _max; + } + + int count(void) const { + return _count; + } +}; + +int main(int argc,char **argv) +{ + int verbose=0; + std::string mask_f; + static struct option long_options[] = { + {"verbose", no_argument, &verbose, 1}, + {"quiet", no_argument, &verbose, 0}, + {"mask", required_argument, 0,'m'}, + + {0, 0, 0, 0} + }; + + for (;;) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + int c = getopt_long (argc, argv, "vqm:", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) break; + + switch (c) + { + case 0: + break; + case 'v': + std::cout << "Version: 0.1" << std::endl; + return 0; + case 'm': + mask_f=optarg; + break; + case '?': + /* getopt_long already printed an error message. */ + default: + show_usage (argv[0]); + return 1; + } + } + + if((argc - optind) < 2) { + show_usage (argv[0]); + return 1; + } + + try + { + minc_1_reader rdr1; + rdr1.open(argv[optind]); + + minc_1_reader rdr2; + rdr2.open(argv[optind+1]); + + if(rdr1.dim_no()!=rdr2.dim_no() ) + { + std::cerr<<"Different number of dimensions!"<<std::endl; + return 1; + } + unsigned long size=1; + + for(int i=0;i<5;i++) + { + if(rdr1.ndim(i)!=rdr2.ndim(i)) + std::cerr<<"Different dimensions length! "<<std::endl; + + if(rdr1.ndim(i)>0) size*=rdr1.ndim(i); + } + + for(int i=0;i<5;i++) + { + if(rdr1.nspacing(i)!=rdr2.nspacing(i) ) + std::cerr<<"Different step size! "<<std::endl; + } + + std::vector<unsigned char> mask(size,1); + if(!mask_f.empty()) + { + minc_1_reader rdr_m; + rdr_m.open(mask_f.c_str()); + + for(int i=0;i<5;i++) + { + if(rdr1.ndim(i)!=rdr_m.ndim(i)) + std::cerr<<"Different mask dimensions length! "<<std::endl; + + if(rdr1.nspacing(i)!=rdr_m.nspacing(i) ) + std::cerr<<"Different mask step size! "<<std::endl; + } + rdr_m.setup_read_byte(); + load_standard_volume<unsigned char>(rdr_m,&mask[0]); + } + + rdr1.setup_read_double(); + rdr2.setup_read_double(); + + std::vector<double> buffer1(size),buffer2(size); + + load_standard_volume<double>(rdr1,&buffer1[0]); + load_standard_volume<double>(rdr2,&buffer2[0]); + + find_min_max<double> f1,f2; + + //get min and max + f1=std::for_each(buffer1.begin(), buffer1.end(), f1); + f2=std::for_each(buffer2.begin(), buffer2.end(), f2); + + if( verbose ) + { + std::cout<<"Volume 1 min="<<(int)f1.min()<<" max="<<(int)f1.max()<<" count="<<f1.count()<<std::endl; + std::cout<<"Volume 2 min="<<(int)f2.min()<<" max="<<(int)f2.max()<<" count="<<f2.count()<<std::endl; + } + + unsigned char low= std::min<double>(f1.min(), f2.min()); + unsigned char hi = std::max<double>(f1.max(), f2.max()); + + int v1=0,v2=0; + double a=0.0,b=0.0,c=0.0,d=0.0; + for(int i=0; i<size ; i++ ) + { + + if(mask[i]>0) + { + a+=std::min<double>(buffer1[i],buffer2[i]); + b+=std::max<double>(buffer1[i],buffer2[i]); + } + } + + std::cout.precision(10); + std::cout<<a/b<<std::endl; + + + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + return 0; +}
new file mode 100644 --- /dev/null +++ b/ezminc/examples/trilinear_resample.cpp @@ -0,0 +1,129 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : trilinear_resample +@DESCRIPTION: an example of using trilinear resampling algorithm +@COPYRIGHT : + Copyright 2011 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 "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" +#include "minc_1_simple_rw.h" +#include <getopt.h> +#include <stdlib.h> +#include <math.h> +//based on http://www3.interscience.wiley.com/journal/121496529/abstract +using namespace minc; + +void show_usage (const char * prog) +{ + std::cerr<<"Usage: "<<prog<<" <input.mnc> <output.mnc> [--step <f> --verbose ]"<<std::endl; +} + +int main(int argc,char **argv) +{ + int verbose=0; + int csv=0; + int kappa=0,specificity=0,sensitivity=0; + int jaccard=0; + double _step=1.0; + static struct option long_options[] = { + {"verbose", no_argument, &verbose, 1}, + {"quiet", no_argument, &verbose, 0}, + {"step", required_argument, 0, 's'}, + {0, 0, 0, 0} + }; + + for (;;) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + int c = getopt_long (argc, argv, "vq", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) break; + + switch (c) + { + case 0: + break; + case 'v': + std::cout << "Version: 0.1" << std::endl; + return 0; + case 's': + _step=atof(optarg); + break; + case '?': + /* getopt_long already printed an error message. */ + default: + show_usage (argv[0]); + return 1; + } + } + + if((argc - optind) < 2) { + show_usage (argv[0]); + return 1; + } + + try + { + minc_1_reader rdr; + rdr.open(argv[optind],true); + minc::minc_info new_info; + + //rdr.setup_read_float(); + simple_volume<float> input_vol,output_vol; + load_simple_volume<float>(rdr,input_vol); + new_info=rdr.info(); + + minc::fixed_vec<3,float> old_step; + minc::fixed_vec<3,float> old_start,new_start; + minc::fixed_vec<3,int> new_len; + + for(int i=1;i<4;i++) + { + old_step[i-1]=new_info[rdr.map_space(i)].step; + old_start[i-1]=new_info[rdr.map_space(i)].start; + + float len=(new_info[rdr.map_space(i)].length)*old_step[i-1]; + + new_info[rdr.map_space(i)].start-=old_step[i-1]; + new_info[rdr.map_space(i)].step=_step; + new_info[rdr.map_space(i)].start+=_step/2; + new_start[i-1]=new_info[rdr.map_space(i)].start; + + new_len[i-1]=new_info[rdr.map_space(i)].length=ceil(fabs(len/_step)); + } + + output_vol.resize(new_len); + + for(int z=0;z<new_len[2];z++) + for(int y=0;y<new_len[1];y++) + for(int x=0;x<new_len[0];x++) + { + minc::fixed_vec<3,float> cc=IDX<float>(x*_step,y*_step,z*_step); + + cc+=new_start; + cc/=old_step; + cc-=old_start; + + output_vol.set(x,y,z,input_vol.interpolate(cc[0],cc[1],cc[2])); + } + minc_1_writer wrt; + wrt.open(argv[optind+1],new_info,2,NC_FLOAT); + save_simple_volume<float>(wrt,output_vol); + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + return 0; +}
new file mode 100644 --- /dev/null +++ b/ezminc/examples/volume_avg.cpp @@ -0,0 +1,148 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : volume_avg +@DESCRIPTION: an example of calculating volume average +@COPYRIGHT : + Copyright 2009 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 "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" +#include "minc_1_simple_rw.h" +#include <getopt.h> +#include <math.h> + +using namespace minc; + +void show_usage(const char *name) +{ + std::cerr + << "Usage: "<<name<<" <input1> .... <inputn> <output> " << std::endl + << "\tn should be more than 1"<< std::endl + << "Optional parameters:" << std::endl + << "\t--verbose be verbose" << std::endl + << "\t--clobber clobber the output files" << std::endl + << "\t--sd <sd.mnc> "<< std::endl; +} + +int main(int argc,char **argv) +{ + int clobber=0; + int verbose=0; + std::string sd_f; + + static struct option long_options[] = + { + {"verbose", no_argument, &verbose, 1}, + {"quiet", no_argument, &verbose, 0}, + {"clobber", no_argument, &clobber, 1}, + {"sd", required_argument, 0, 's'}, + {0, 0, 0, 0} + }; + + int c; + for (;;) + { + /* getopt_long stores the option index here. */ + int option_index = 0; + + c = getopt_long (argc, argv, "s", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) + { + case 0: + break; + case 's': + sd_f=optarg; + break; + case '?': + /* getopt_long already printed an error message. */ + default: + show_usage(argv[0]); + return 1; + } + } + + if ((argc - optind) < 3) + { + show_usage(argv[0]); + return 1; + } + + std::string output=argv[argc-1]; //last argument is output file... maybe we should make it a parameter instead? + argc-=optind; + + if(!clobber && !access (output.c_str(), F_OK)) + { + std::cerr << output.c_str () << " Exists!" << std::endl; + return 1; + } + + try + { + + minc_1_reader rdr1; + rdr1.open(argv[optind]); + minc_float_volume _avg; + + load_simple_volume<float>(rdr1,_avg); + + minc_float_volume _sd(_avg); + minc_float_volume _tmp(_avg); + + + for(int i=0;i<_avg.c_buf_size();i++) + { + _sd.c_buf()[i]=_avg.c_buf()[i]*_avg.c_buf()[i]; + } + + for(int i=1;i<(argc-1);i++) + { + minc_1_reader rdr2; + rdr2.open(argv[optind+i]); + if(!is_same(rdr1,rdr2)) + { + return 1; + } + + load_simple_volume<float>(rdr2,_tmp); + _avg+=_tmp; + _tmp*=_tmp; + _sd+=_tmp; + } + _avg/=(float)(argc-1); + for(int i=0;i<_avg.c_buf_size();i++) + { + _sd.c_buf()[i]=sqrt(_sd.c_buf()[i]/(argc-1) - _avg.c_buf()[i]*_avg.c_buf()[i] ); + } + minc_1_writer wrt; + wrt.open(output.c_str(),rdr1.info(),2,NC_FLOAT); + save_simple_volume<float>(wrt,_avg); + + if(!sd_f.empty()) + { + minc_1_writer wrt2; + wrt2.open(sd_f.c_str(),rdr1.info(),2,NC_FLOAT); + save_simple_volume<float>(wrt2,_sd); + } + + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + + return 0; +} +
new file mode 100644 --- /dev/null +++ b/ezminc/examples/volume_msq_dist.cpp @@ -0,0 +1,98 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : volume_msq_dist +@DESCRIPTION: an example of calculating mean squared dissimilarity +@COPYRIGHT : + Copyright 2011 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 "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" + +using namespace minc; + +int main(int argc,char **argv) +{ + + try + { + if(argc<4) { + std::cerr<<"Usage: "<<argv[0]<<" <input1.mnc> <input2.mnc> <mask.mnc>"<<std::endl; + return 1; + } + minc_1_reader rdr1; + rdr1.open(argv[1]); + + minc_1_reader rdr2; + rdr2.open(argv[2]); + + minc_1_reader rdr_m; + rdr_m.open(argv[3]); + + if(rdr1.dim_no()!=rdr2.dim_no() || rdr1.dim_no()!=rdr_m.dim_no()) + { + std::cerr<<"Different number of dimensions!"<<std::endl; + return 1; + } + unsigned long size=1; + for(int i=0;i<5;i++) + { + if(rdr1.ndim(i)!=rdr2.ndim(i) || rdr1.ndim(i)!=rdr_m.ndim(i)) + { + std::cerr<<"Different dimensions length! "<<std::endl; + } + if(rdr1.ndim(i)>0) size*=rdr1.ndim(i); + } + + for(int i=0;i<5;i++) + { + if(rdr1.nspacing(i)!=rdr2.nspacing(i) || rdr1.nspacing(i)!=rdr_m.nspacing(i)) + { + std::cerr<<"Different step size! "<<std::endl; + } + } + + //std::cout<<size<<std::endl; + rdr1.setup_read_float(); + rdr2.setup_read_float(); + rdr_m.setup_read_byte(); + + std::vector<float> buffer1(size),buffer2(size); + std::vector<unsigned char> mask(size); + + load_standard_volume<float>(rdr1,&buffer1[0]); + load_standard_volume<float>(rdr2,&buffer2[0]); + load_standard_volume<unsigned char>(rdr_m,&mask[0]); + + double avg=0; + int cnt=0; + for(int i=0;i<size;i++) + { + if(!mask[i]) continue; + double d=buffer1[i]-buffer2[i]; + avg+=d*d; + cnt++; + } + if(cnt) + avg/=cnt; + if( rdr1.ndim(0)==3 ) //this is a grid file + avg*=3; + std::cout.precision(10); + std::cout<<avg<<std::endl; + + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + + return 0; +} +
new file mode 100644 --- /dev/null +++ b/ezminc/examples/volume_similarity.cpp @@ -0,0 +1,259 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : volume_similarity +@DESCRIPTION: an example of calculating volume similarity metrics +@COPYRIGHT : + Copyright 2011 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 "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" +#include <getopt.h> +#include <algorithm> + +using namespace minc; + +void show_usage (const char * prog) +{ + std::cout<<"Program calculates volume similarity metrics"<<std::endl + <<"if multiple labels are present, similarity metrics will be calculated for each label separately"<<std::endl + <<"based on : M. Feuerman and A. R. Miller " + <<"\"Relationships between statistical measures of agreement: sensitivity, specificity and kappa\"" + <<" Journal of Evaluation in Clinical Practice vol. 14 no. 5 pp 930-933 2008"<<std::endl + <<"http://dx.doi.org/10.1111/j.1365-2753.2008.00984.x"<<std::endl<<std::endl + <<"Usage: "<<prog<<" <input1.mnc> <input2.mnc> [--kappa --sensitivity --specificity --verbose --jaccard --csv]"<<std::endl; + +} + +template<class T>class find_min_max +{ + public: + T _min; + T _max; + bool _initialized; + int _count; + + find_min_max():_initialized(false),_min(0),_max(0),_count(0) + { + } + + void operator()(const T& v) + { + if(_initialized) + { + if(v<_min) _min=v; + if(v>_max) _max=v; + } else { + _initialized=true; + _min=v; + _max=v; + } + _count++; + } + + const T& min(void) const { + return _min; + } + + const T& max(void) const{ + return _max; + } + + int count(void) const { + return _count; + } +}; + +int main(int argc,char **argv) +{ + int verbose=0; + int csv=0; + int kappa=0,specificity=0,sensitivity=0; + int jaccard=0; + static struct option long_options[] = { + {"verbose", no_argument, &verbose, 1}, + {"quiet", no_argument, &verbose, 0}, + {"kappa", no_argument, &kappa, 1}, + {"sensitivity", no_argument, &sensitivity, 1}, + {"specificity", no_argument, &specificity, 1}, + {"jaccard", no_argument, &jaccard, 1}, + {"csv", no_argument, &csv, 1}, + {0, 0, 0, 0} + }; + + for (;;) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + int c = getopt_long (argc, argv, "vq", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) break; + + switch (c) + { + case 0: + break; + case 'v': + std::cout << "Version: 0.1" << std::endl; + return 0; + case '?': + /* getopt_long already printed an error message. */ + default: + show_usage (argv[0]); + return 1; + } + } + + if((argc - optind) < 2) { + show_usage (argv[0]); + return 1; + } + + if(! (sensitivity||specificity||kappa||jaccard) ) //no options selected, do all + { + verbose=1; + sensitivity=1; + specificity=1; + kappa=1; + jaccard=1; + } + + try + { + minc_1_reader rdr1; + rdr1.open(argv[optind]); + + minc_1_reader rdr2; + rdr2.open(argv[optind+1]); + + if(rdr1.dim_no()!=rdr2.dim_no() ) + { + std::cerr<<"Different number of dimensions!"<<std::endl; + return 1; + } + unsigned long size=1; + + for(int i=0;i<5;i++) + { + if(rdr1.ndim(i)!=rdr2.ndim(i)) + std::cerr<<"Different dimensions length! "<<std::endl; + + if(rdr1.ndim(i)>0) size*=rdr1.ndim(i); + } + + for(int i=0;i<5;i++) + { + if(rdr1.nspacing(i)!=rdr2.nspacing(i) ) + std::cerr<<"Different step size! "<<std::endl; + } + + rdr1.setup_read_byte(); + rdr2.setup_read_byte(); + + std::vector<unsigned char> buffer1(size),buffer2(size); + + load_standard_volume<unsigned char>(rdr1,&buffer1[0]); + load_standard_volume<unsigned char>(rdr2,&buffer2[0]); + + find_min_max<unsigned char> f1,f2; + + //get min and max + f1=std::for_each(buffer1.begin(), buffer1.end(), f1); + f2=std::for_each(buffer2.begin(), buffer2.end(), f2); + + if( verbose && !csv) + { + //std::cout<<buffer1.size() << std::endl; + //std::cout<<buffer1.begin()<<" "<<buffer1.end()<<std::endl; + + std::cout<<"Volume 1 min="<<(int)f1.min()<<" max="<<(int)f1.max()<<" count="<<f1.count()<<std::endl; + std::cout<<"Volume 2 min="<<(int)f2.min()<<" max="<<(int)f2.max()<<" count="<<f2.count()<<std::endl; + } + + unsigned char low= std::min<unsigned char>(f1.min(), f2.min()); + unsigned char hi = std::max<unsigned char>(f1.max(), f2.max()); + + if(low==0) low=1; //assume 0 is background + + + for(unsigned char label=low; label<=hi; label++) + { + int v1=0,v2=0; + double a=0.0,b=0.0,c=0.0,d=0.0; + for(int i=0; i<size ; i++ ) + { + if( buffer1[i]==label ) v1++; + if( buffer2[i]==label ) v2++; + if( buffer1[i]==label && buffer2[i]==label ) a++; + if( buffer1[i]==label && buffer2[i]!=label ) c++; + if( buffer1[i]!=label && buffer2[i]==label ) b++; + if( buffer1[i]!=label && buffer2[i]!=label ) d++; + } + double _kappa=0.0; + double _sensitivity=0.0; + double _specificity=0.0; + double _jaccard=0.0; + + if(v1>0 && v2>0) + { + //_kappa=v1v2*2.0/(v1+v2); + _kappa=a*2.0/(v1+v2); + + _sensitivity=a/(a+c); + _specificity=d/(b+d); + + _jaccard=a/(a+c+b); + } + + std::cout.precision(10); + + if( hi!=low && verbose && !csv) + std::cout<<"Label: "<<(int)label<<std::endl; + + if( csv ) + { + if(low!=hi) + std::cout<<(int)label<<","; + + std::cout<<_kappa<<","; + std::cout<<_sensitivity<<","; + std::cout<<_specificity<<","; + std::cout<<_jaccard<<std::endl; + } else { + if( kappa ){ + if(verbose) std::cout<<"Kappa "; + std::cout<<_kappa<<std::endl; + } + if( sensitivity ) + { + if(verbose) std::cout<<"Sensitivity "; + std::cout<<_sensitivity<<std::endl; + } + if( specificity ) + { + if(verbose) std::cout<<"Specificity "; + std::cout<<_specificity<<std::endl; + } + if( jaccard ) + { + if(verbose) std::cout<<"Jaccard similarity "; + std::cout<<_jaccard<<std::endl; + } + } + } + + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + return 0; +}
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__
new file mode 100644 --- /dev/null +++ b/ezminc/tests/minc_com.cpp @@ -0,0 +1,48 @@ +#include "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" +#include "minc_1_simple_rw.h" + +using namespace minc; + +int main(int argc,char **argv) +{ + try + { + if(argc<2) { + std::cerr<<"Usage: "<<argv[0]<<" <input.mnc> "<<std::endl; + return 1; + } + minc_1_reader rdr; + rdr.open(argv[1],true); + simple_volume<float> vol; + load_simple_volume<float>(rdr,vol); + //calculate COM + fixed_vec<3,int> i; + fixed_vec<3,double> w; + double total=0; + double tx=0.0,ty=0.0,tz=0.0; + + for(i[2]=0;i[2]<vol.dim(2);i[2]++) + for(i[1]=0;i[1]<vol.dim(1);i[1]++) + for(i[0]=0;i[0]<vol.dim(0);i[0]++) + { + w=vol.voxel_to_world(i); + tx+=w[0]*vol.get(i); + ty+=w[1]*vol.get(i); + tz+=w[2]*vol.get(i); + total+=vol.get(i); + } + tx/=total; + ty/=total; + tz/=total; + std::cout<<tx<<","<<ty<<","<<tz<<std::endl; + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + + return 0; +} +
new file mode 100644 --- /dev/null +++ b/ezminc/tests/minc_com_4d.cpp @@ -0,0 +1,70 @@ +#include "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple_rw.h" + +using namespace minc; + +int main(int argc,char **argv) +{ + try + { + if(argc<2) { + std::cerr<<"Usage: "<<argv[0]<<" <input.mnc> "<<std::endl; + return 1; + } + minc_1_reader rdr; + rdr.open(argv[1],true); + simple_4d_volume<float> vol; + load_4d_volume<float>(rdr,vol); + //calculate COM + fixed_vec<3,int> i; + fixed_vec<3,double> w; + + double total=0.0; + double tx=0.0,ty=0.0,tz=0.0,tT=0.0; + + //std::cout<<"T-start:"<<vol.t_start()<<std::endl; + //std::cout<<"T-step:"<<vol.t_step()<<std::endl; + + for(int t=0;t<vol.frames();t++) + { + double rt=t*vol.t_step()+vol.t_start(); + + for(i[2]=0;i[2]<vol.dim(2);i[2]++) + for(i[1]=0;i[1]<vol.dim(1);i[1]++) + for(i[0]=0;i[0]<vol.dim(0);i[0]++) + { + w=vol.voxel_to_world(i); + + double v=vol.get(i,t); + + tx+=w[0]*v; + ty+=w[1]*v; + tz+=w[2]*v; + tT+=rt *v; + + total+=v; + //std::cout<<v<<"\t"; + } + //std::cout<<std::endl; + //std::cout<<rt<<"\t"<<tT<<"\t"<<std::flush; + std::cout<<"."<<std::flush; + } + std::cout<<std::endl; + + tx/=total; + ty/=total; + tz/=total; + tT/=total; + + std::cout<<tx<<","<<ty<<","<<tz<<","<<tT<<std::endl; + + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + + return 0; +} +
new file mode 100644 --- /dev/null +++ b/ezminc/tests/minc_rw_test.cpp @@ -0,0 +1,129 @@ +#include "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" + +using namespace minc; + +template<class T>class volume_3d +{ + protected: + T* _data; + int _x,_y,_z; + public: + + volume_3d(T* data,int x,int y,int z):_data(data),_x(x),_y(y),_z(z) + { + } + + volume_3d(std::vector<T> data,int x,int y,int z):_data(&data[0]),_x(x),_y(y),_z(z) + { + } + + T& operator()(int x,int y,int z) + { + return _data[x+y*_x+z*_x*_y]; + } + +}; + +int main(int argc,char **argv) +{ + try + { + if(argc<4) { + std::cerr<<"Usage: "<<argv[0]<<" <input.mnc> <output.mnc> <output2.mnc>"<<std::endl; + return 1; + } + minc_1_reader rdr; + rdr.open(argv[1]); + int i; + for(i=0;i<rdr.dim_no();i++) + std::cout<<rdr.dim(i).name<<" "<<rdr.dim(i).length<<std::endl; + std::cout<<"Slice len="<<rdr.slice_len()<<std::endl; + std::cout<<"History:"<<rdr.history().c_str()<<std::endl; + for(int v=0;v<rdr.var_number();v++) + { + std::string var=rdr.var_name(v); + for(int a=0;a<rdr.att_number(v);a++) + { + std::string aname=rdr.att_name(v,a); + nc_type dt=rdr.att_type(v,aname.c_str()); + + std::cout<<var.c_str()<<":"<<aname.c_str()<<" "; + if(dt==NC_CHAR) + std::cout<<rdr.att_value_string(v,aname.c_str()); + else if(dt=NC_DOUBLE) + { + std::vector<double> val=rdr.att_value_double(v,aname.c_str()); + for(int d=0;d<val.size();d++) + std::cout<<val[d]<<"\t"; + } else { + std::cout<<"???"; + } + std::cout<<std::endl; + } + } + + rdr.setup_read_float(); + + minc_1_writer wrt; + wrt.open(argv[2],rdr.info(),2,NC_FLOAT,true); + wrt.setup_write_float(); + std::vector<float> v(rdr.slice_len()); + + int c=0; + double s=0; + for(rdr.begin(),wrt.begin();!rdr.last();rdr.next_slice(),wrt.next_slice()) + { + //std::cout<<wrt.current_slice()[0]<<std::endl; + rdr.read(&v[0]); + for(int i=0;i<rdr.slice_len();i++) + { + s+=v[i]; + c++; + } + wrt.write(&v[0]); + } + s/=c; + //std::cout<<wrt._image_range[0]<<" "<<wrt._image_range[1]<<std::endl; + std::cout<<s<<std::endl; + wrt.copy_headers(rdr); + wrt.append_history("minc_rw_test test1\n"); + + //second test + unsigned long size=1; + for(i=0;i<rdr.dim_no();i++) + size*=rdr.dim(i).length; + + minc_1_writer wrt2; + wrt2.open(argv[3],rdr.info(),3,NC_SHORT,false); + wrt2.setup_write_float(); + + std::vector<float> buffer(size); + load_standard_volume<float>(rdr,&buffer[0]); + double avg2=0; + //for(int i=0;i<size;i++) + // avg2+=buffer[i]; + volume_3d<float> volume(buffer,rdr.ndim(dim_info::DIM_X),rdr.ndim(dim_info::DIM_Y),rdr.ndim(dim_info::DIM_Z)); + for(int z=0;z<rdr.ndim(dim_info::DIM_Z);z++) + for(int y=0;y<rdr.ndim(dim_info::DIM_Y);y++) + for(int x=0;x<rdr.ndim(dim_info::DIM_X);x++) + { + avg2+=volume(x,y,z); + } + + avg2/=size; + std::cout<<"avg2 "<<avg2<<std::endl; + + save_standard_volume<float>(wrt2,&buffer[0]); + wrt2.copy_headers(rdr); + wrt2.append_history("minc_rw_test test2\n"); + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + + return 0; +} +
new file mode 100644 --- /dev/null +++ b/ezminc/tests/minc_rw_test2.cpp @@ -0,0 +1,42 @@ +#include "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" +#include "minc_io_simple_volume.h" + +using namespace minc; + +int main(int argc,char **argv) +{ + try + { + if(argc<3) { + std::cerr<<"Usage: "<<argv[0]<<" <input.mnc> <output.mnc>"<<std::endl; + return 1; + } + minc_1_reader rdr; + rdr.open(argv[1],true); + rdr.setup_read_float(); + simple_volume<float> vol; + vol.resize(rdr.ndim(1),rdr.ndim(2),rdr.ndim(3)); + load_non_standard_volume<float>(rdr,vol.c_buf()); + //rdr.close(); + for(int z=0;z<vol.dim(2);z++) + for(int y=0;y<vol.dim(1);y++) + for(int x=0;x<vol.dim(0);x++) + { + vol(x,y,z)=x; + } + minc_1_writer wrt; + wrt.open(argv[2],rdr.info(),3,NC_FLOAT,false); + wrt.setup_write_float(); + save_non_standard_volume<float>(wrt,vol.c_buf()); + + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + + return 0; +} +
new file mode 100644 --- /dev/null +++ b/ezminc/tests/minc_rw_test_4d.cpp @@ -0,0 +1,51 @@ +#include "minc_1_simple_rw.h" +#include <iostream> + +using namespace minc; + +int main(int argc,char **argv) +{ + try + { + if(argc<3) { + std::cerr<<"Usage: "<<argv[0]<<" <input.mnc> <output.mnc>"<<std::endl; + return 1; + } + minc_1_reader rdr; + rdr.open(argv[1]); + + if(rdr.dim_no()==3|| (rdr.dim_no()==4 && rdr.ndim(4)>0 )) + { + if(rdr.datatype()==NC_FLOAT || rdr.datatype()==NC_SHORT) + { + std::cout<<"Reading float volume"<<std::endl; + simple_4d_volume<float> vol; + + load_4d_volume(rdr,vol); + save_minc_file(argv[2],vol,"test",&rdr,rdr.datatype(),rdr.is_signed()); + } else if(rdr.datatype()==NC_BYTE) { + std::cout<<"Reading byte volume"<<std::endl; + simple_4d_volume<unsigned char> vol; + + load_4d_volume(rdr,vol); + save_minc_file(argv[2],vol,"test",&rdr,rdr.datatype(),rdr.is_signed()); + } + } else if((rdr.dim_no()==4|| rdr.dim_no()==5)&&rdr.ndim(0)==3) { //we are dealing with vectors + std::cout<<"Reading vector volume"<<std::endl; + simple_4d_volume< fixed_vec<3,float> > vol; + + load_4d_volume(rdr,vol); + save_minc_file(argv[2],vol,"test",&rdr,rdr.datatype(),rdr.is_signed()); + } + + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + + return 0; +} + + +
new file mode 100644 --- /dev/null +++ b/ezminc/tests/minc_rw_test_simple.cpp @@ -0,0 +1,43 @@ +#include "minc_1_rw.h" +#include <iostream> +#include "minc_1_simple.h" + +using namespace minc; + +int main(int argc,char **argv) +{ + try + { + if(argc<3) { + std::cerr<<"Usage: "<<argv[0]<<" <input.mnc> <output.mnc>"<<std::endl; + return 1; + } + minc_1_reader rdr; + rdr.open(argv[1],true); + rdr.setup_read_float(); + + minc_1_writer wrt; + for(int i=0;i<3;i++) + { + std::cout<<rdr.info()[i].step<<" "<<rdr.info()[i].start<<std::endl; + } + wrt.open(argv[2],rdr.info(),3,NC_FLOAT,false); + wrt.setup_write_float(); + minc_input_iterator<float> in(rdr); + minc_output_iterator<float> out(wrt); + float c=0.0; + for(in.begin(),out.begin();!in.last();in.next(),out.next()) + { + out.value(in.value()+c); + c++; + } + + } catch (const minc::generic_error & err) { + std::cerr << "Got an error at:" << err.file () << ":" << err.line () << std::endl; + std::cerr << err.msg()<<std::endl; + return 1; + } + + return 0; +} +
new file mode 100644 --- /dev/null +++ b/ezminc/tests/transformpoint.cpp @@ -0,0 +1,29 @@ +#include <volume_io.h> +#include <iostream> + + +int main(int argc, char **argv) +{ + if(argc<5) + { + std::cerr<<"Usage:"<<argv[0]<<"<XFM file> X Y Z"<<std::endl; + return 1; + } + double x,y,z; + double _x,_y,_z; + + x=atof(argv[2]); + y=atof(argv[3]); + z=atof(argv[4]); + + General_transform _xfm; + if(input_transform_file((char*)argv[1], &_xfm)!=OK) + { + std::cerr<<"Error reading:"<<argv[1]<<std::endl; + return 1; + } + general_transform_point( &_xfm, x, y, z,&_x, &_y, &_z); + delete_general_transform(&_xfm); + std::cout<<_x<<" "<<_y<<" "<<_z<<std::endl; + return 0; +}; \ No newline at end of file
--- a/libsrc/netcdf_convenience.c +++ b/libsrc/netcdf_convenience.c @@ -229,7 +229,7 @@ @INPUT : command - command to execute infile - input file outfile - output file - header_only - TRUE if only header of minc file is needed + header_only - ignored @OUTPUT : (none) @RETURNS : status of decompress command (zero = success) @DESCRIPTION: Routine to execute a decompression command on a minc file. @@ -244,18 +244,9 @@ PRIVATE int execute_decompress_command(char *command, char *infile, char *outfile, int header_only) { - int oldncopts; char whole_command[1024]; int status; - FILE *pipe, *output; - char buffer[1024]; - int successful_ncopen; - int ibuf; - int nread; - int processid; -#define BYTES_PER_OPEN (1024*64) -#define NUM_BUFFERS_PER_OPEN ((BYTES_PER_OPEN - 1) / sizeof(buffer) + 1) #if !(HAVE_WORKING_FORK && HAVE_SYSTEM && HAVE_POPEN) @@ -263,105 +254,12 @@ #else /* Unix */ - - if (!header_only) { /* Decompress the whole file */ - - (void) sprintf(whole_command, "exec %s %s > %s 2> /dev/null", - command, infile, outfile); - status = system(whole_command); - } - else { /* We just need to decompress enough for - the header */ - - /* Set up the command and open the pipe (we defer opening the output - file until we have read something) */ - (void) sprintf(whole_command, "exec %s %s 2> /dev/null", - command, infile); - pipe = popen(whole_command, "r"); - output = NULL; - - /* Loop until we have successfully opened the minc file (the header - is all there) */ - successful_ncopen = FALSE; - while (!successful_ncopen && !feof(pipe)) { - - /* Loop, copying buffers from pipe to file. If the file hasn't been - opened, then open it */ - for (ibuf=0; (ibuf < NUM_BUFFERS_PER_OPEN) && - ((nread = - fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0); - ibuf++) { - if (output == NULL) { - output = fopen(outfile, "w"); - if (output == NULL) { - (void) fclose(pipe); - return 1; - } - } - if (fwrite(buffer, sizeof(char), nread, output) != nread) { - (void) fclose(output); - (void) fclose(pipe); - return 1; - } - } /* End of for loop, copying from pipe to output */ - if (fflush(output)) { - (void) fclose(output); - (void) fclose(pipe); - return 1; - } - -#if MINC2 - successful_ncopen = hdf_access(outfile); - if (successful_ncopen) { - break; - } -#endif /* MINC2 */ - - /* Try to open minc file. There seems to be a bug in NetCDF 2.3.2 - - when the header is not all present in the file, we get a core - dump if ncopts does not have NC_FATAL set. There error is - reported to be in NC_free_var (var.c:54), called from - NC_free_array (array.c:348). This is all called from - NC_new_cdf (cdf.c:84), in NC_free_cdf, just after the error - return from xdr_cdf. The work-around is to fork, set fatal - and check the return status of the child. */ - oldncopts = ncopts; ncopts = 0; - processid = fork(); - if (!processid) { /* Child */ - - /* Close all filehandles to avoid buffer flushing problems */ - { - int f; - f=getdtablesize()-1; /* could use OPEN_MAX-1 instead */ - if (f < 2) f = 2; /* At least close 0,1,2 */ - for (; f >= 0; f--) { - (void) close(f); - } - } - - /* Try the open */ - ncopts = NC_FATAL; - status = ncopen(outfile, NC_NOWRITE); - (void) ncclose(status); - exit(0); - - } - - /* Parent gets status from child */ - (void) waitpid(processid, &status, 0); - if (status == 0) { - successful_ncopen = TRUE; - } - ncopts = oldncopts; - - } /* End of while, waiting for successful ncopen */ - - (void) fclose(output); - (void) fclose(pipe); - - status = !successful_ncopen; - - } /* End of if !header_only else */ + /* we now ignore header_only and always uncompress the whole + * file as the previous "header only" hack that used to work + * on MINC1 files doesn't work reliably with MINC2 */ + (void) sprintf(whole_command, "exec %s %s > %s 2> /dev/null", + command, infile, outfile); + status = system(whole_command); /* Return the status */ return status;
new file mode 100644 --- /dev/null +++ b/minc4itk/CMakeLists.txt @@ -0,0 +1,57 @@ +FIND_PACKAGE(ITK REQUIRED) + +IF(NOT ITK_LIBRARIES) + MESSAGE( FATAL_ERROR "ITK libraries are not found!") +ENDIF(NOT ITK_LIBRARIES) + +IF(NOT ITK_INCLUDE_DIRS) + MESSAGE( FATAL_ERROR "ITK include directories are not found!") +ENDIF(NOT ITK_INCLUDE_DIRS ) + +#OPTION(BUILD_ITK_PLUGIN "Build ITK plugin" OFF) +OPTION(BUILD_MINC4ITK_EXAMPLES "Build minc4itk examples" ON) + +LINK_DIRECTORIES(${ITK_LIBRARY_DIRS}) + +INCLUDE_DIRECTORIES( + ${ITK_INCLUDE_DIRS} + ) + +SET( MINC4ITK_HEADERS + itkMincImageIOFactory.h + minc_general_transform.h + minc_helpers.h + itkMincImageIO.h + ) + +SET( MINC4ITK_SRC + minc_helpers.cxx + itkMincImageIO.cxx + itkMincImageIOFactory.cxx + ) + +ADD_LIBRARY( minc4itk ${MINC4ITK_HEADERS} ${MINC4ITK_SRC}) + +TARGET_LINK_LIBRARIES( minc4itk + minc_io + ${ITK_LIBRARIES} + itkvnl_algo + itkvnl + ${minc_LIB} + ${volume_io_LIB} + m + z ) + +#VF ITK plugin is disabled for now +#IF(BUILD_ITK_PLUGIN) +#ADD_LIBRARY( minc4itk_plugin SHARED minc4itk_plugin.cxx) +#TARGET_LINK_LIBRARIES( minc4itk_plugin minc4itk) +#INSTALL(TARGETS minc4itk_plugin LIBRARY DESTINATION lib) +#ENDIF(BUILD_ITK_PLUGIN) + +INSTALL(TARGETS minc4itk ARCHIVE DESTINATION lib) +INSTALL(FILES ${MINC4ITK_HEADERS} DESTINATION include) + +IF(BUILD_MINC4ITK_EXAMPLES) +add_subdirectory(examples) +ENDIF(BUILD_MINC4ITK_EXAMPLES) \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/minc4itk/examples/CMakeLists.txt @@ -0,0 +1,17 @@ +LINK_LIBRARIES( minc4itk ) + + + + +ADD_EXECUTABLE(itk_convert itk_convert.cpp) +ADD_EXECUTABLE(itk_distance itk_distance.cpp) +ADD_EXECUTABLE(itk_dti itk_dti.cpp) +ADD_EXECUTABLE(itk_resample itk_resample.cpp) +ADD_EXECUTABLE(volume_2_csv volume_2_csv.cpp) + + +INSTALL(TARGETS + itk_convert + itk_distance + itk_resample + DESTINATION bin)
new file mode 100644 --- /dev/null +++ b/minc4itk/examples/itk_convert.cpp @@ -0,0 +1,287 @@ +#include <iostream> + +#include <itkImage.h> +#include <itkImageFileReader.h> +#include <itkImageFileWriter.h> +#include <itkImageIOFactory.h> +#include <itkImageIOBase.h> +#include <itkFlipImageFilter.h> + +#include "itkMincImageIOFactory.h" +#include "itkMincImageIO.h" + +#include <getopt.h> + +void show_usage (const char *name) +{ + std::cerr + << "Usage: "<<name<<" <input> <output> " << std::endl + << "--clobber clobber output files"<<std::endl + << "--verbose be verbose"<<std::endl + << "--inv-x invert X axis"<<std::endl + << "--inv-y invert Y axis"<<std::endl + << "--inv-z invert Z axis"<<std::endl + << "--center set origin to the center of the image"<<std::endl +; +} +typedef itk::ImageIOBase IOBase; +typedef itk::SmartPointer<IOBase> IOBasePointer; + +template<class ImageType> void load_and_save_image(IOBase* base, + const char *fname, + bool inv_x=false, + bool inv_y=false, + bool inv_z=false, + bool center=false, + bool verbose=false) +{ + typename itk::ImageFileReader<ImageType >::Pointer reader = itk::ImageFileReader<ImageType >::New(); + typename itk::FlipImageFilter<ImageType >::Pointer flip=itk::FlipImageFilter<ImageType >::New(); + reader->SetImageIO(base); + reader->SetFileName(base->GetFileName()); + reader->Update(); + + typename ImageType::Pointer img=reader->GetOutput(); + + /* WRITING */ + if(verbose) + std::cout<<"Writing "<<fname<<"..."<<std::endl; + + + + if(inv_x||inv_y||inv_z) + { + typename itk::FlipImageFilter<ImageType >::FlipAxesArrayType arr; + arr[0]=inv_x; + arr[1]=inv_y; + arr[2]=inv_z; + flip->SetFlipAxes(arr); + flip->SetInput(img); + flip->Update(); + img=flip->GetOutput(); + } + + if(center)//move origin to the center of the image + { + typename ImageType::RegionType r=img->GetLargestPossibleRegion(); + std::vector<double> corner[3]; + + typename ImageType::IndexType idx; + typename ImageType::PointType c; + + idx[0]=r.GetIndex()[0]+r.GetSize()[0]/2.0; + idx[1]=r.GetIndex()[1]+r.GetSize()[1]/2.0; + idx[2]=r.GetIndex()[2]+r.GetSize()[2]/2.0; + + img->TransformIndexToPhysicalPoint(idx,c); + + typename ImageType::PointType org=img->GetOrigin(); + + org[0]-=c[0]; + org[1]-=c[1]; + org[2]-=c[2]; + + img->SetOrigin(org); + } + + typename itk::ImageFileWriter< ImageType >::Pointer writer = itk::ImageFileWriter<ImageType >::New(); + writer->SetFileName(fname); + writer->SetInput( img ); + writer->Update(); + +} + +int main(int argc,char **argv) +{ + int verbose=0; + int clobber=0; + int inv_x=0,inv_y=0,inv_z=0,center=0; + //char *history = time_stamp(argc, argv); //maybe we should free it afterwards + + static struct option long_options[] = { + {"verbose", no_argument, &verbose, 1}, + {"quiet", no_argument, &verbose, 0}, + {"clobber", no_argument, &clobber, 1}, + {"inv-x", no_argument, &inv_x, 1}, + {"inv-y", no_argument, &inv_y, 1}, + {"inv-z", no_argument, &inv_z, 1}, + {"center", no_argument, ¢er, 1}, + {0, 0, 0, 0} + }; + + int c; + for (;;) + { + /* getopt_long stores the option index here. */ + int option_index = 0; + + c = getopt_long (argc, argv, "", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) + { + case 0: + break; + case '?': + /* getopt_long already printed an error message. */ + default: + show_usage (argv[0]); + return 1; + } + } + + if((argc - optind)<2) + { + show_usage(argv[0]); + return 1; + } + std::string input=argv[optind]; + std::string output=argv[optind+1]; + + if (!clobber && !access (output.c_str(), F_OK)) + { + std::cerr << output.c_str () << " Exists!" << std::endl; + return 1; + } + + try + { + //registering the MINC_IO factory + itk::ObjectFactoryBase::RegisterFactory(itk::MincImageIOFactory::New()); + /* READING */ + if(verbose) + std::cout<<"Reading "<<input.c_str()<<"..."<<std::endl; + + //try to figure out what we have got + IOBasePointer io = itk::ImageIOFactory::CreateImageIO(input.c_str(), itk::ImageIOFactory::ReadMode ); + + if(!io) + throw itk::ExceptionObject("Unsupported image file type"); + + io->SetFileName(input.c_str()); + io->ReadImageInformation(); + + size_t nd = io->GetNumberOfDimensions(); + size_t nc = io->GetNumberOfComponents(); + itk::ImageIOBase::IOComponentType ct = io->GetComponentType(); + std::string ct_s = io->GetComponentTypeAsString(ct); + + if(verbose) + { + std::cout<<"dimensions:"<<nd<<std::endl + <<"components:"<<nc<<std::endl + <<"type:"<<ct_s.c_str()<<std::endl; + } + + if(nd==3 && nc==1) + { + if(verbose) std::cout<<"Writing 3D image..."<<std::endl; + switch(ct) + { + case itk::ImageIOBase::UCHAR : + load_and_save_image<itk::Image<unsigned char, 3> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::CHAR : + load_and_save_image<itk::Image<char, 3> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::USHORT : + load_and_save_image<itk::Image<unsigned short, 3> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::SHORT : + load_and_save_image<itk::Image<short, 3> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::INT : + load_and_save_image<itk::Image<int, 3> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::UINT: + load_and_save_image<itk::Image<unsigned int, 3> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::FLOAT : + load_and_save_image<itk::Image<float, 3> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::DOUBLE: + load_and_save_image<itk::Image<double, 3> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + default: + itk::ExceptionObject("Unsupported component type"); + } + } else if((nd==4 && nc==1)) { + if(verbose) std::cout<<"Writing 4D image..."<<std::endl; + switch(ct) + { + case itk::ImageIOBase::UCHAR: + load_and_save_image<itk::Image<unsigned char, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::CHAR: + load_and_save_image<itk::Image<char, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::USHORT: + load_and_save_image<itk::Image<unsigned short, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::SHORT: + load_and_save_image<itk::Image<short, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::INT: + load_and_save_image<itk::Image<int, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::UINT: + load_and_save_image<itk::Image<unsigned int, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::FLOAT: + load_and_save_image<itk::Image<float, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::DOUBLE: + load_and_save_image<itk::Image<double, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + default: + itk::ExceptionObject("Unsupported component type"); + } + } else if((nd==3 && nc>1)) { + if(verbose) std::cout<<"Writing multicomponent 3D image..."<<std::endl; + + switch(ct) + { + case itk::ImageIOBase::UCHAR: + load_and_save_image<itk::VectorImage<unsigned char, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::CHAR: + load_and_save_image<itk::VectorImage<char, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::USHORT: + load_and_save_image<itk::VectorImage<unsigned short, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::SHORT: + load_and_save_image<itk::VectorImage<short, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::INT: + load_and_save_image<itk::VectorImage<int, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::UINT: + load_and_save_image<itk::VectorImage<unsigned int, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::FLOAT: + load_and_save_image<itk::VectorImage<float, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + case itk::ImageIOBase::DOUBLE: + load_and_save_image<itk::VectorImage<double, 4> >(io,output.c_str(),inv_x,inv_y,inv_z,center,verbose); + break; + default: + itk::ExceptionObject("Unsupported component type"); + } + } else { + throw itk::ExceptionObject("Unsupported number of dimensions"); + } + + } + + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught !" << std::endl; + std::cerr << err << std::endl; + return 2; + } + return 0; +}
new file mode 100644 --- /dev/null +++ b/minc4itk/examples/itk_distance.cpp @@ -0,0 +1,139 @@ +/* ----------------------------- 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. +---------------------------------------------------------------------------- */ +#include <unistd.h> +#include <getopt.h> +#include <iostream> +#include <itkDanielssonDistanceMapImageFilter.h> +#include <itkSignedDanielssonDistanceMapImageFilter.h> +#include <time_stamp.h> // for creating minc style history entry +#include "itkMincImageIOFactory.h" +#include "itkMincImageIO.h" +#include "minc_helpers.h" + +//#include <minc_wrappers.h> + +using namespace minc; +using namespace std; +void show_usage(const char *name) +{ + std::cerr + << "Usage: "<<name<<" <input> <output> " << endl + << "--verbose be verbose " << endl + << "--clobber clobber output files"<<endl + << "--signed produce signed distance map"<<endl; +} + +int main (int argc, char **argv) +{ + + int verbose=1; + double sigma=0.5; + double keep=1.0; + int order=5; + int approx=0; + int ss=0; + int clobber=0; + char *history = time_stamp(argc, argv); + + //int voxel_neibourhood=5; + static struct option long_options[] = { + {"clobber", no_argument, &clobber, 1}, + {"verbose", no_argument, &verbose, 1}, + {"quiet", no_argument, &verbose, 0}, + {"signed",no_argument, &ss, 1}, + {0, 0, 0, 0} + }; + + for (;;) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + int c = getopt_long (argc, argv, "vq", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) break; + + switch (c) + { + // case 'n': + // voxel_neibourhood=atoi(optarg);break; + case 0: + break; + case '?': + /* getopt_long already printed an error message. */ + default: + show_usage (argv[0]); + return 1; + } + } + if ((argc - optind) < 2) { + show_usage (argv[0]); + return 1; + } + std::string input_f=argv[optind], out_f=argv[optind+1]; + + // check if the file already present + if (!clobber && !access (out_f.c_str (), F_OK)) + { + cerr << out_f.c_str () << " Exists!" << endl; + return 1; + } + + try + { + itk::ObjectFactoryBase::RegisterFactory(itk::MincImageIOFactory::New()); + itk::ImageFileReader<minc::mask3d >::Pointer reader = itk::ImageFileReader<minc::mask3d >::New(); + + //initializing the reader + reader->SetFileName(input_f.c_str()); + reader->Update(); + + minc::mask3d::Pointer input=reader->GetOutput(); + minc::image3d::Pointer output; + + typedef itk::DanielssonDistanceMapImageFilter< minc::mask3d, minc::image3d > + DistanceMapFilter; + typedef itk::SignedDanielssonDistanceMapImageFilter< minc::mask3d, minc::image3d > + SignedDistanceMapFilter; + + if(ss) + { + SignedDistanceMapFilter::Pointer dist(SignedDistanceMapFilter::New()); + dist->SetInput(input); + dist->Update(); + output=dist->GetOutput(); + } else { + DistanceMapFilter::Pointer dist(DistanceMapFilter::New()); + dist->SetInput(input); + dist->Update(); + output=dist->GetOutput(); + } + + minc::copy_metadata(output,input); + minc::append_history(output,history); + free(history); + + itk::ImageFileWriter< minc::image3d >::Pointer writer = itk::ImageFileWriter<minc::image3d >::New(); + writer->SetFileName(out_f.c_str()); + writer->SetInput( output ); + writer->Update(); + + } catch (const minc::generic_error & err) { + cerr << "Got an error at:" << err.file () << ":" << err.line () << endl; + cerr << err.msg()<<endl; + return 1; + } + return 0; +}
new file mode 100644 --- /dev/null +++ b/minc4itk/examples/itk_dti.cpp @@ -0,0 +1,148 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : itk_dti +@DESCRIPTION: an example of processing DTI information +@COPYRIGHT : + Copyright 2011 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 <iostream> + +#include <itkMetaDataObject.h> +#include <itkVectorImage.h> + +#include <itkImage.h> + +#include <itkImageFileReader.h> +#include <itkImageFileWriter.h> +#include <itkImageIOFactory.h> +#include <itkDiffusionTensor3DReconstructionImageFilter.h> +#include <itkTensorFractionalAnisotropyImageFilter.h> + +#include "itkMincImageIOFactory.h" +#include "itkMincImageIO.h" + +typedef itk::VectorImage<float, 3> DTIImageType; +typedef itk::DiffusionTensor3DReconstructionImageFilter<float,float,float> DtiReconstructionFilter; +typedef itk::Image< itk::DiffusionTensor3D< float >, 3 > TensorImage; +typedef DtiReconstructionFilter::GradientDirectionContainerType Gradients; +typedef itk::Image<float,3> faImage; +typedef itk::TensorFractionalAnisotropyImageFilter<TensorImage,faImage > FAFilter; + + +// a helper function for minc reading +template <class T> typename T::Pointer load_minc(const char *file) +{ + typedef itk::MincImageIO ImageIOType; + ImageIOType::Pointer minc2ImageIO = ImageIOType::New(); + + typename itk::ImageFileReader<T>::Pointer reader = itk::ImageFileReader<T>::New(); + + reader->SetFileName(file); + reader->SetImageIO( minc2ImageIO ); + reader->Update(); + + return reader->GetOutput(); +} + +// a helper function for minc writing +template <class T> void save_minc(const char *file,typename T::ConstPointer img) +{ + typedef itk::MincImageIO ImageIOType; + ImageIOType::Pointer minc2ImageIO = ImageIOType::New(); + + typename itk::ImageFileWriter< T >::Pointer writer = itk::ImageFileWriter<T>::New(); + writer->SetFileName(file); + writer->SetImageIO( minc2ImageIO ); + writer->SetInput( img ); + writer->Update(); +} + + +int main(int argc,char **argv) +{ + if(argc<3) + { + std::cerr<<"Usage:"<<argv[0]<<" <in.mnc> <out_tensor.mnc> <out_eign.mnc> "<<std::endl; + return 1; + } + + try + { + std::cout<<"Reading "<<argv[1]<<"..."<<std::endl; + + typedef itk::MincImageIO ImageIOType; + ImageIOType::Pointer minc2ImageIO = ImageIOType::New(); + DTIImageType::Pointer img=load_minc<DTIImageType>(argv[1]); + DtiReconstructionFilter::Pointer filter=DtiReconstructionFilter::New(); + filter->SetNumberOfThreads(1); //as per request in documentation + + //extracting the parameters of acquisition from the metadata + typedef std::vector<double> double_vector; + double_vector bvalues,direction_x,direction_y,direction_z; + + //making sure that all vcrtors contain the same number of parameters (just in case) + if(!itk::ExposeMetaData<double_vector>( img->GetMetaDataDictionary() , "acquisition:bvalues",bvalues) || + !itk::ExposeMetaData<double_vector>( img->GetMetaDataDictionary() , "acquisition:direction_x",direction_x) || + !itk::ExposeMetaData<double_vector>( img->GetMetaDataDictionary() , "acquisition:direction_y",direction_y) || + !itk::ExposeMetaData<double_vector>( img->GetMetaDataDictionary() , "acquisition:direction_z",direction_z)) + { + std::cerr<<"Image doesn't have information on DTI gradients, can't process!"<<std::endl; + return 2; + } + if(bvalues.size()!=direction_x.size() || + bvalues.size()!=direction_y.size() || + bvalues.size()!=direction_z.size() ) + { + std::cerr<<"Different number of components of gradients"<<std::endl; + return 2; + } + std::cout<<"Found "<<bvalues.size()<<" gradient directions"<<std::endl; + + //converting metadata representation to the format used by DiffusionTensor3DReconstructionImageFilter + Gradients::Pointer gradients=Gradients::New(); + gradients->resize(direction_x.size()); + double bval=0; + //copying values one-by-one + for(int i=0;i<bvalues.size();i++) + if(bval<bvalues[i]) bval=bvalues[i]; + + for(int i=0;i<direction_x.size();i++) + { + (*gradients)[i][0]=direction_x[i]*sqrt(bvalues[i]/bval); + (*gradients)[i][1]=direction_y[i]*sqrt(bvalues[i]/bval); + (*gradients)[i][2]=direction_z[i]*sqrt(bvalues[i]/bval); + } + + std::cout<<"Calculating tensor..."<<std::endl; + filter->SetGradientImage(gradients,img); + filter->SetBValue(bval); + filter->Update(); + + std::cout<<"Writing "<<argv[2]<<"..."<<std::endl; + save_minc<TensorImage>(argv[2],filter->GetOutput() ); + std::cout<<"Calculating FA ..."<<std::endl; + + FAFilter::Pointer fa=FAFilter::New(); + fa->SetInput(filter->GetOutput()); + fa->SetNumberOfThreads(1); //just in case + fa->Update(); + + std::cout<<"Writing "<<argv[3]<<"..."<<std::endl; + save_minc<faImage>(argv[3],fa->GetOutput() ); + + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught !" << std::endl; + std::cerr << err << std::endl; + return 2; + } + return 0; +}
new file mode 100644 --- /dev/null +++ b/minc4itk/examples/itk_resample.cpp @@ -0,0 +1,259 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : itk_resample +@DESCRIPTION: an example of using spline itnerpolation with MINC xfm transform +@COPYRIGHT : + Copyright 2011 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 <iostream> +#include <fstream> +#include <getopt.h> +#include <vector> +#include <valarray> +#include <math.h> +#include <limits> +#include <unistd.h> + +#include <itkResampleImageFilter.h> +#include <itkAffineTransform.h> +#include <itkNearestNeighborInterpolateImageFunction.h> +#include <itkBSplineInterpolateImageFunction.h> +#include <minc_general_transform.h> + +#include <unistd.h> +#include <getopt.h> +#include <time_stamp.h> // for creating minc style history entry + + +#include <itkImageFileReader.h> +#include <itkImageFileWriter.h> +#include <itkImageIOFactory.h> + +#include "itkMincImageIOFactory.h" +#include "itkMincImageIO.h" +#include "minc_helpers.h" + +//typedef itk::MincImageIO ImageIOType; +typedef itk::BSplineInterpolateImageFunction< minc::image3d, double, double > InterpolatorType; +typedef itk::ResampleImageFilter<minc::image3d, minc::image3d> FilterType; +typedef minc::XfmTransform<double,3,3> TransformType; + +using namespace std; + +void show_usage (const char * prog) +{ + std::cerr + << "Usage: "<<prog<<" <input> <output.mnc> " << std::endl + << "--clobber overwrite files" << std::endl + << "--like <example> (default behaviour analogous to use_input_sampling)"<<std::endl + << "--transform <xfm_transform> "<<std::endl + << "--order <n> spline order, default 2 "<<std::endl + << "--uniformize <step> - will make a volume with uniform step size and no direction cosines" << std::endl + << "--invert_transform - apply inverted transform"<<std::endl; +} + +void generate_uniform_sampling(FilterType* flt, const minc::image3d* img,double step) +{ + //obtain physical coordinats of all image corners + minc::image3d::RegionType r=img->GetLargestPossibleRegion(); + std::vector<double> corner[3]; + for(int i=0;i<8;i++) + { + minc::image3d::IndexType idx; + minc::image3d::PointType c; + idx[0]=r.GetIndex()[0]+r.GetSize()[0]*(i%2); + idx[1]=r.GetIndex()[1]+r.GetSize()[1]*((i/2)%2); + idx[2]=r.GetIndex()[2]+r.GetSize()[2]*((i/4)%2); + img->TransformIndexToPhysicalPoint(idx,c); + for(int j=0;j<3;j++) + corner[j].push_back(c[j]); + } + minc::image3d::IndexType start; + FilterType::SizeType size; + FilterType::OriginPointType org; + minc::image3d::SpacingType spc; + spc.Fill(step); + for(int j=0;j<3;j++) + { + std::sort(corner[j].begin(),corner[j].end()); + size[j]=ceil((corner[j][7]-corner[j][0])/step); + org[j]=corner[j][0]; + } + minc::image3d::DirectionType identity; + identity.SetIdentity(); + flt->SetOutputDirection(identity); + start.Fill(0); + flt->SetOutputStartIndex(start); + flt->SetSize(size); + flt->SetOutputOrigin(org); + flt->SetOutputSpacing(spc); +} + +int main (int argc, char **argv) +{ + int verbose=0, clobber=0,skip_grid=0; + int order=2; + std::string like_f,xfm_f,output_f,input_f; + double uniformize=0.0; + int invert=0; + char *history = time_stamp(argc, argv); + + static struct option long_options[] = { + {"verbose", no_argument, &verbose, 1}, + {"quiet", no_argument, &verbose, 0}, + {"clobber", no_argument, &clobber, 1}, + {"like", required_argument, 0, 'l'}, + {"transform", required_argument, 0, 't'}, + {"order", required_argument, 0, 'o'}, + {"uniformize", required_argument, 0, 'u'}, + {"invert_transform", no_argument, &invert, 1}, + {0, 0, 0, 0} + }; + + for (;;) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + int c = getopt_long (argc, argv, "vqcl:t:o:u:", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) break; + + switch (c) + { + case 0: + break; + case 'v': + cout << "Version: 0.1" << endl; + return 0; + case 'l': + like_f=optarg; break; + case 't': + xfm_f=optarg; break; + case 'o': + order=atoi(optarg);break; + case 'u': + uniformize=atof(optarg);break; + case '?': + /* getopt_long already printed an error message. */ + default: + show_usage (argv[0]); + return 1; + } + } + + if ((argc - optind) < 2) { + show_usage(argv[0]); + return 1; + } + input_f=argv[optind]; + output_f=argv[optind+1]; + + if (!clobber && !access (output_f.c_str (), F_OK)) + { + std::cerr << output_f.c_str () << " Exists!" << std::endl; + return 1; + } + + try + { + itk::ObjectFactoryBase::RegisterFactory(itk::MincImageIOFactory::New()); + itk::ImageFileReader<minc::image3d >::Pointer reader = itk::ImageFileReader<minc::image3d >::New(); + + //initializing the reader + reader->SetFileName(input_f.c_str()); + reader->Update(); + + minc::image3d::Pointer in=reader->GetOutput(); + + FilterType::Pointer filter = FilterType::New(); + + //creating coordinate transformation objects + TransformType::Pointer transform = TransformType::New(); + if(!xfm_f.empty()) + { + //reading a minc style xfm file + transform->OpenXfm(xfm_f.c_str()); + if(!invert) transform->Invert(); //should be inverted by default to walk through target space + filter->SetTransform( transform ); + } + + //creating the interpolator + InterpolatorType::Pointer interpolator = InterpolatorType::New(); + interpolator->SetSplineOrder(order); + filter->SetInterpolator( interpolator ); + filter->SetDefaultPixelValue( 0 ); + + //this is for processing using batch system + filter->SetNumberOfThreads(1); + + minc::image3d::Pointer like=0; + if(!like_f.empty()) + { + itk::ImageFileReader<minc::image3d >::Pointer reader = itk::ImageFileReader<minc::image3d >::New(); + reader->SetFileName(like_f.c_str()); + reader->Update(); + if(uniformize!=0.0) + { + generate_uniform_sampling(filter,reader->GetOutput(),uniformize); + } else { + filter->SetOutputParametersFromImage(reader->GetOutput()); + filter->SetOutputDirection(reader->GetOutput()->GetDirection()); + } + like=reader->GetOutput(); + like->DisconnectPipeline(); + } + else + { + if(uniformize!=0.0) + { + generate_uniform_sampling(filter,in,uniformize); + } else { + //we are using original sampling + filter->SetOutputParametersFromImage(in); + filter->SetOutputDirection(in->GetDirection()); + } + } + + filter->SetInput(in); + filter->Update(); + //copy the metadate information, for some reason it is not preserved + //filter->GetOutput()->SetMetaDataDictionary(reader->GetOutput()->GetMetaDataDictionary()); + minc::image3d::Pointer out=filter->GetOutput(); + minc::copy_metadata(out,in); + minc::append_history(out,history); + free(history); + + //correct dimension order + if(like.IsNotNull()) + minc::copy_dimorder(out,like); + + //generic file writer + itk::ImageFileWriter< minc::image3d >::Pointer writer = itk::ImageFileWriter<minc::image3d >::New(); + writer->SetFileName(output_f.c_str()); + + writer->SetInput( out ); + //writer->UseInputMetaDataDictionaryOn(); + + writer->Update(); + + return 0; + } catch (const minc::generic_error & err) { + cerr << "Got an error at:" << err.file () << ":" << err.line () << endl; + return 1; + } + catch( itk::ExceptionObject & err ) + { + std::cerr << "ExceptionObject caught !" << std::endl; + std::cerr << err << std::endl; + return 2; + } + return 0; +};
new file mode 100644 --- /dev/null +++ b/minc4itk/examples/volume_2_csv.cpp @@ -0,0 +1,156 @@ +/* ----------------------------- MNI Header ----------------------------------- +@NAME : volume_2_csv +@DESCRIPTION: an example of converting a minc file volume to a text format +@COPYRIGHT : + Copyright 2011 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 <iostream> +#include <fstream> +#include <getopt.h> +#include <vector> +#include <valarray> +#include <math.h> +#include <limits> +#include <unistd.h> +#include <itkImageFileReader.h> +#include <itkImageFileWriter.h> +#include <itkImageIOFactory.h> + +#include "itkMincImageIOFactory.h" +#include "itkMincImageIO.h" + +#include "minc_helpers.h" + + +using namespace std; +using namespace minc; + +void show_usage (const char * prog) +{ + std::cerr<<"Usage:"<<prog<<" in.mnc out.csv --mask <mask> --clobber --terse"<<endl; +} + +typedef itk::MincImageIO ImageIOType; + + +int main (int argc, char **argv) +{ + std::string mask_f; + int verbose=0,clobber=0; + int terse=0; + static struct option long_options[] = { + {"verbose", no_argument, &verbose, 1}, + {"quiet", no_argument, &verbose, 0}, + {"clobber", no_argument, &clobber, 1}, + {"mask", required_argument, 0, 'm'}, + {"terse", no_argument, &terse, 1}, + {0, 0, 0, 0} + }; + + for (;;) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + int c = getopt_long (argc, argv, "m:vd:k:i:", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) break; + + switch (c) + { + case 0: + break; + case 'v': + cout << "Version: 0.1" << endl; + return 0; + case 'm': + mask_f=optarg; break; + case '?': + /* getopt_long already printed an error message. */ + default: + show_usage (argv[0]); + return 1; + } + } + + if((argc - optind) < 2) { + show_usage (argv[0]); + return 1; + } + if (!clobber && !access(argv[optind+1], F_OK)) + { + cerr << argv[optind+1] << " Exists!" << endl; + return 1; + } + + try + { + minc::mask3d::Pointer mask(minc::mask3d::New()); + + //creating a minc reader + ImageIOType::Pointer minc2ImageIO = ImageIOType::New(); + + itk::ImageFileReader<minc::image3d >::Pointer reader = itk::ImageFileReader<minc::image3d >::New(); + //initializing the reader + reader->SetFileName(argv[optind]); + reader->SetImageIO( minc2ImageIO ); + reader->Update(); + + minc::image3d::Pointer img=reader->GetOutput(); + + + if(!mask_f.empty()) + { + itk::ImageFileReader<minc::mask3d >::Pointer reader = itk::ImageFileReader<minc::mask3d >::New(); + //initializing the reader + reader->SetFileName(mask_f.c_str()); + reader->SetImageIO( minc2ImageIO ); + reader->Update(); + mask=reader->GetOutput(); + } + const minc::mask3d::RegionType& reg=mask->GetLargestPossibleRegion(); + + ofstream out(argv[optind+1]); + if(out.bad()) + REPORT_ERROR ("can't open file"); + + image3d_iterator it(img,img->GetLargestPossibleRegion()); + if(!terse) out<<"x,y,z,I"<<endl; + if(out.bad()) + REPORT_ERROR ("can't write to file"); + + mask3d::IndexType idx; + + for(it.GoToBegin();!it.IsAtEnd();++it) { + tag_point p; + img->TransformIndexToPhysicalPoint(it.GetIndex(),p); + + if(!mask_f.empty()) + { + mask->TransformPhysicalPointToIndex(p,idx); + if(!reg.IsInside(idx) || !mask->GetPixel(idx)) + continue; + } + + if(terse) + out<<it.Value()<<endl; + else + out<<p[0]<<","<<p[1]<<","<<p[2]<<","<<it.Value()<<endl; + if(out.bad()) + REPORT_ERROR ("can't write to file"); + } + return 0; + } catch (const minc::generic_error & err) { + cerr << "Got an error at:" << err.file () << ":" << err.line () << endl; + return 1; + } + return 0; +};
new file mode 100644 --- /dev/null +++ b/minc4itk/itkMincImageIO.cxx @@ -0,0 +1,720 @@ +/*========================================================================= +Program: Insight Segmentation & Registration Toolkit +Module: $RCSfile: itkMincImageIO.cxx,v $ +Language: C++ +Date: $Date: 2005/12/08 19:18:48 $ +Version: $Revision: 1.22 $ + +Copyright (c) Insight Software Consortium. All rights reserved. +See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. + +This software is distributed WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ + +#include "itkMincImageIO.h" +#include "itkIOCommon.h" +#include "itkExceptionObject.h" +#include "itkMetaDataObject.h" +#include <itkMatrix.h> +#include <itksys/SystemTools.hxx> +#include <vnl/vnl_math.h> +#include <zlib.h> +#include <stdio.h> +#include <stdlib.h> +#include <vector> + +using namespace minc; + +namespace itk +{ + + MincImageIO::MincImageIO():_rdr(NULL),_wrt(NULL) + { + } + + void MincImageIO::clean(void) + { + if(_rdr) delete _rdr; + if(_wrt) delete _wrt; + _rdr=NULL; + _wrt=NULL; + } + + MincImageIO::~MincImageIO() + { + clean(); + } + + void MincImageIO::PrintSelf(std::ostream& os, Indent indent) const + { + Superclass::PrintSelf(os, indent); + if(_rdr) + os<<"MINC file is opened for reading"<<std::endl; + if(_wrt) + os<<"MINC file is opened for writing"<<std::endl; + } + + + bool MincImageIO::CanReadFile( const char* FileNameToRead ) + { + std::string filename = FileNameToRead; + //taken from original MINC2ImageIO + + if( filename.empty()) + { + itkDebugMacro(<<"No filename specified."); + return false; + } + + std::string::size_type mncPos = filename.rfind(".mnc"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 4) ) + { + return true; + } + + mncPos = filename.rfind(".MNC"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 4) ) + { + return true; + } + + mncPos = filename.rfind(".mnc2"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 5) ) + { + return true; + } + + mncPos = filename.rfind(".MNC2"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 5) ) + { + return true; + } + + mncPos = filename.rfind(".mnc.gz"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 7) ) + { + return true; + } + + mncPos = filename.rfind(".MNC.GZ"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 7) ) + { + return true; + } + + return false; + } + + void MincImageIO::ReadImageInformation() + { + clean(); + try + { + _rdr=new minc_1_reader; + _rdr->open(m_FileName.c_str(),true); //read in positive direction, always + SetNumberOfDimensions((_rdr->ndim(1)>0?1:0)+(_rdr->ndim(2)>0?1:0)+(_rdr->ndim(3)>0?1:0)); + + //SetMetaDataDictionary(thisDic); + // set number of dimensions for ITK + int image_max_length=_rdr->var_length(MIimagemax); + int image_min_length=_rdr->var_length(MIimagemin); + bool slice_normalized=image_max_length>1; + /* + std::cout<<"Image max length="<<image_max_length<<std::endl; + std::cout<<"Image min length="<<image_min_length<<std::endl;*/ + + switch(_rdr->datatype()) + { + case NC_BYTE: + if(slice_normalized) + m_ComponentType=FLOAT; + else + m_ComponentType=UCHAR; + break; + + case NC_SHORT: + + if(slice_normalized) + m_ComponentType=FLOAT; + else + m_ComponentType=_rdr->is_signed()?SHORT:USHORT; + break; + + case NC_INT: + if(slice_normalized) + m_ComponentType=FLOAT; + else + m_ComponentType=_rdr->is_signed()?INT:UINT; + break; + + case NC_FLOAT: + m_ComponentType=FLOAT; + break; + + case NC_DOUBLE: + m_ComponentType=DOUBLE; + break; + + default: + throw ExceptionObject(__FILE__,__LINE__,"Unsupported data type"); + } + + if(_rdr->ndim(0)==0 && _rdr->ndim(4)==0) //vector dimension + { + m_PixelType=SCALAR; + //SetNumberOfComponents(1); + } else { + m_PixelType=VECTOR; + if(_rdr->ndim(0)>0 && _rdr->ndim(4)>0) + throw ExceptionObject(__FILE__,__LINE__,"Combining time and vector dimension in one file is not supported!"); + SetNumberOfComponents(_rdr->ndim(0)+_rdr->ndim(4)); + } + + for(int i=1,c=0; i < 4; i++) + { + if(_rdr->ndim(i)<=0) continue; + SetDimensions(c,_rdr->ndim(i)); + SetSpacing(c,_rdr->nspacing(i)); + SetOrigin(c,_rdr->nstart(i)); + c++; + } + + if(GetNumberOfDimensions()==3) + { + itk::Matrix< double, 3,3 > dir_cos; + for(int i=1; i < 4; i++) + { + std::vector<double> dc(3); + if(_rdr->have_dir_cos(i)) + { + for(int j=0;j<3;j++) + { + dc[j]=_rdr->ndir_cos(i,j); + dir_cos[j][i-1]=_rdr->ndir_cos(i,j); + } + } else { + for(int j=0;j<3;j++) + { + dc[j]=((i-1)==j?1:0); + dir_cos[j][i-1]=((i-1)==j?1:0); + } + } + SetDirection(i-1,dc); + } + + itk::Vector< double,3> origin; + itk::Vector< double,3> o_origin; + for(int j=0;j<3;j++) + o_origin[j]=GetOrigin(j); + origin=dir_cos*o_origin; + for(int j=0;j<3;j++) + SetOrigin(j,origin[j]); + } else { //we are not rotating the origin according to direction cosines in this case + for(int i=1,c=0; i < 5; i++) + { + if(_rdr->ndim(i)<=0) continue; + std::vector<double> dc(3); + for(int j=0;j<3;j++) + dc[j]=_rdr->ndir_cos(i,j); + SetDirection(c,dc); + c++; + } + } + ComputeStrides(); + + //now, we are just assuming that all the volumes with short,int and float data types are real, + //and those that are char are not + itk::MetaDataDictionary &thisDic=GetMetaDataDictionary(); + std::string classname(GetNameOfClass()); + itk::EncapsulateMetaData<std::string>(thisDic,ITK_InputFilterName, classname); + //now let's store some metadata + //internally image is always stored + + /*itk::EncapsulateMetaData<itk::SpatialOrientation::ValidCoordinateOrientationFlags> + (thisDic,ITK_CoordinateOrientation, itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_LPI);*/ + + itk::EncapsulateMetaData(thisDic,"datatype",_rdr->datatype()); + itk::EncapsulateMetaData(thisDic,"signed" ,_rdr->is_signed()); + + /*switch(_rdr->datatype()) + { + case NC_SHORT: + + itk::EncapsulateMetaData<std::string>(thisDic,ITK_OnDiskStorageTypeName,_rdr->is_signed()?std::string(typeid(short).name()):std::string(typeid(unsigned short).name())); + break; + + case NC_BYTE: + itk::EncapsulateMetaData<std::string>(thisDic,ITK_OnDiskStorageTypeName,_rdr->is_signed()?std::string(typeid(char).name()):std::string(typeid(unsigned char).name())); + break; + + case NC_FLOAT: + itk::EncapsulateMetaData<std::string>(thisDic,ITK_OnDiskStorageTypeName,std::string(typeid(float).name())); + break; + }*/ + + if(_rdr->ndim(4)) //we have got time dimension + { + itk::EncapsulateMetaData<double>(thisDic,"tstart",_rdr->nstart(4)); + itk::EncapsulateMetaData<double>(thisDic,"tstep",_rdr->nspacing(4)); + } + + std::vector<std::string> dimorder; + for(int i=0;i<_rdr->dim_no();i++) + { + dimorder.push_back(_rdr->info()[i].name); + } + itk::EncapsulateMetaData(thisDic,"dimorder", dimorder); + itk::EncapsulateMetaData<std::string>(thisDic,"history", _rdr->history()); + //walk through all the minc attributes, and store them + for(int i=0;i<_rdr->var_number();i++) + { + std::string var=_rdr->var_name(i); + + if(var=="rootvariable" || + var=="image" || + var=="image-min" || + var=="image-max" || + var=="xspace" || + var=="yspace" || + var=="zspace" || + var=="time" || + var=="vector_dimension" ) + continue; + int var_id=_rdr->var_id(var.c_str()); + for(int j=0;j<_rdr->att_number(var_id);j++) + { + std::string att=_rdr->att_name(var_id,j); + std::string path=var+":"+att; + //std::cout<<path.c_str()<<" "; + switch(_rdr->att_type(var_id,att.c_str())) + { + case NC_CHAR: + itk::EncapsulateMetaData<std::string>(thisDic,path, _rdr->att_value_string(var_id,att.c_str())); + //std::cout<<"string"; + break; + case NC_INT: + itk::EncapsulateMetaData<std::vector<int> >(thisDic,path, _rdr->att_value_int(var_id,att.c_str())); + //std::cout<<"int"; + break; + case NC_DOUBLE: + itk::EncapsulateMetaData<std::vector<double> >(thisDic,path, _rdr->att_value_double(var_id,att.c_str())); + //std::cout<<"double"; + break; + case NC_SHORT: + itk::EncapsulateMetaData<std::vector<short> >(thisDic,path, _rdr->att_value_short(var_id,att.c_str())); + break; + case NC_BYTE: + itk::EncapsulateMetaData<std::vector<unsigned char> >(thisDic,path, _rdr->att_value_byte(var_id,att.c_str())); + break; + default: + //std::cout<<"Unknown"; + break; //don't know what it is, skipping for now! + } + //std::cout<<std::endl; + } + } + + } catch(const minc::generic_error & err) { + throw ExceptionObject(__FILE__,__LINE__,"Error reading minc file"); + } + } + + void MincImageIO::Read(void* buffer) + { + //TODO: add support for IORegion ? + //ImageIORegion regionToRead = this->GetIORegion(); + switch(GetComponentType()) + { + case CHAR: + case UCHAR: + _rdr->setup_read_byte(false); + load_non_standard_volume<unsigned char>(*_rdr,(unsigned char*)buffer); + break; + case INT: + _rdr->setup_read_int(false); + load_non_standard_volume<int>(*_rdr,(int*)buffer); + break; + case UINT: + _rdr->setup_read_uint(false); + load_non_standard_volume<unsigned int>(*_rdr,(unsigned int*)buffer); + break; + case SHORT: + _rdr->setup_read_short(false); + load_non_standard_volume<short>(*_rdr,(short*)buffer); + break; + case USHORT: + _rdr->setup_read_ushort(false); + load_non_standard_volume<unsigned short>(*_rdr,(unsigned short*)buffer); + break; + case FLOAT: + _rdr->setup_read_float(); + load_non_standard_volume<float>(*_rdr,(float*)buffer); + break; + case DOUBLE: + _rdr->setup_read_double(); + load_non_standard_volume<double>(*_rdr,(double*)buffer); + break; + default: + throw ExceptionObject(__FILE__, __LINE__,"Unsupported data type"); + } + delete _rdr; + _rdr=NULL; + } + + bool MincImageIO::CanWriteFile(const char * FileNameToWrite) + { + std::string filename = FileNameToWrite; + //taken from original MINC2ImageIO + + if( filename.empty()) + { + itkDebugMacro(<<"No filename specified."); + return false; + } + + std::string::size_type mncPos = filename.rfind(".mnc"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 4) ) + { + return true; + } + + mncPos = filename.rfind(".MNC"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 4) ) + { + return true; + } + + mncPos = filename.rfind(".mnc2"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 5) ) + { + return true; + } + + mncPos = filename.rfind(".MNC2"); + if ( (mncPos != std::string::npos) + && (mncPos == filename.length() - 5) ) + { + return true; + } + + return false; + } + + void MincImageIO::WriteImageInformation(void) + { + try + { + MetaDataDictionary &thisDic=GetMetaDataDictionary(); + nc_type datatype; + bool is_signed=false; + bool have_vectors=false; + bool have_time=false; + + switch(GetComponentType()) + { + case UCHAR: + case CHAR: + datatype=NC_BYTE; + is_signed=false; + break; + case SHORT: + datatype=NC_SHORT; + is_signed=true; + break; + case USHORT: + datatype=NC_SHORT; + is_signed=false; + break; + case INT: + datatype=NC_INT; + is_signed=true; + break; + case UINT: + datatype=NC_INT; + is_signed=false; + + break; + case FLOAT: + //let's see if there is metadata available + nc_type _datatype; + bool _is_signed; + if( itk::ExposeMetaData(thisDic,"datatype",_datatype) && + itk::ExposeMetaData(thisDic,"signed",_is_signed) ) + { + datatype=_datatype; + is_signed=_is_signed; + } else { + datatype=NC_FLOAT; + is_signed=true; + } + + break; + case DOUBLE: + datatype=NC_DOUBLE; + is_signed=true; + break; + default: + { + throw ExceptionObject(__FILE__, __LINE__,"Unsupported data type"); + } + } + std::vector<std::string> dimorder; + std::vector<int> dimmap(5,-1); + minc_info info; + + if(GetNumberOfComponents()>1 && GetNumberOfComponents()<=3 ) + { + have_vectors=true; + have_time=false; + } else if(GetNumberOfComponents()>3||GetNumberOfDimensions()>3) { + have_vectors=false; + have_time=true; + } + + if(itk::ExposeMetaData(thisDic,"dimorder",dimorder)) + { + //dimmap.resize(dimorder.size()); + for(int i=0,j=0;i<dimorder.size();i++) + { + if(dimorder[i]==MIvector_dimension && have_vectors) + { + dimmap[0]=j++; + } + else if(dimorder[i]==MItime && have_time) + { + dimmap[4]=j++; + } else if(dimorder[i]==MIxspace) { + dimmap[1]=j++; + } else if(dimorder[i]==MIyspace) { + dimmap[2]=j++; + } else if(dimorder[i]==MIzspace) { + dimmap[3]=j++; + } + } + } else { + if(have_vectors) + { + dimmap[0]=0; + } else if(have_time) { + have_vectors=false; + have_time=true; + dimmap[GetNumberOfDimensions()+1]=GetNumberOfDimensions(); + } + dimmap[1]=(have_vectors?1:0)+0; + dimmap[2]=(have_vectors?1:0)+1; + dimmap[3]=(have_vectors?1:0)+2; + } + + int dim_no=GetNumberOfDimensions()+(have_vectors||have_time?1:0); + info.resize(dim_no); + +/* std::cout<<"dimmap:"; + for(int i=0;i<5;i++) + { + std::cout<<dimmap[i]<<","; + } + std::cout<<std::endl;*/ + + for(int i=0;i<GetNumberOfDimensions();i++) + { + int _i=dimmap[i+1];//GetNumberOfDimensions()-i-1+(have_vectors?1:0); + if(_i<0) + { + throw ExceptionObject(__FILE__, __LINE__,"Internal error"); + } + //ERROR! + info[_i].length=GetDimensions(i); + info[_i].step=GetSpacing(i); + info[_i].start=GetOrigin(i); + info[_i].have_dir_cos=true; + for(int j=0;j<3;j++) + info[_i].dir_cos[j]=GetDirection(i)[j]; + + switch(i) + { + case 0: + info[_i].dim=dim_info::DIM_X; + break; + case 1: + info[_i].dim=dim_info::DIM_Y; + break; + case 2: + info[_i].dim=dim_info::DIM_Z; + break; + } + } + if(GetNumberOfDimensions()==3) //we are only rotating 3D volumes + { + vnl_vector< double> start(3); + vnl_vector< double> vorigin(3); + itk::Matrix< double, 3,3 > _dir_cos; + for(int i=0;i<3;i++) + { + vorigin[i]=GetOrigin(i); + for(int j=0;j<3;j++) + _dir_cos[j][i]=GetDirection(i)[j]; + } + start=_dir_cos.GetInverse()*vorigin; //this is not optimal + for(int i=0;i<3;i++) + { + int _i=dimmap[i+1]; + info[_i].start=start[i]; + } + } + //here we assume that we had a grid file + if(have_vectors) + { + int _i=dimmap[0]; + info[_i].length=GetNumberOfComponents(); + info[_i].step=1; + info[_i].start=0; + info[_i].dim=dim_info::DIM_VEC; + info[_i].have_dir_cos=false; + } else if(have_time){ + int _i=dimmap[4]; + info[_i].length=GetNumberOfComponents(); + double tstep=1; + double tstart=0; + itk::ExposeMetaData(thisDic,"tstep",tstep); + itk::ExposeMetaData(thisDic,"tstart",tstart); + + info[_i].step=tstep; + info[_i].start=tstart; + info[_i].dim=dim_info::DIM_TIME; + info[_i].have_dir_cos=false; + } + +/* std::cout<<"info:"; + for(int i=0;i<info.size();i++) + { + switch(info[i].dim) + { + case dim_info::DIM_VEC: + std::cout<<"vector_dimension,";break; + case dim_info::DIM_Z: + std::cout<<"zspace,";break; + case dim_info::DIM_Y: + std::cout<<"yspace,";break; + case dim_info::DIM_X: + std::cout<<"xspace,";break; + default: std::cout<<"Unknown! ";break; + + } + } + std::cout<<std::endl; */ + + //TODO: shuffle info based on the dimnames + _wrt=new minc_1_writer; + _wrt->open(this->GetFileName(), + info, + (datatype==NC_FLOAT||datatype==NC_DOUBLE)? + dim_no:(have_time?dim_no-2:dim_no-1), + datatype,is_signed); + + //let's write some meta information if there is any + for(MetaDataDictionary::ConstIterator it=thisDic.Begin();it!=thisDic.End();++it) + { + const char *d=strchr((*it).first.c_str(),':'); + if(d) + { + std::string var((*it).first.c_str(),d-(*it).first.c_str()); + std::string att(d+1); + itk::MetaDataObjectBase *bs=(*it).second; + const char *tname=bs->GetMetaDataObjectTypeName(); + //std::cout<<var.c_str()<<"\t"<<att.c_str()<<"\t"<<tname<<std::endl; + + //THIS is not good OO style at all :( + if(!strcmp(tname,typeid(std::string).name())) + { + _wrt->insert(var.c_str(),att.c_str(), + dynamic_cast<MetaDataObject<std::string> *>(bs )->GetMetaDataObjectValue().c_str()); + } else if(!strcmp(tname,typeid(std::vector<double>).name())) { + _wrt->insert(var.c_str(),att.c_str(), + dynamic_cast<MetaDataObject<std::vector<double> > * >(bs)->GetMetaDataObjectValue()); + } else if(!strcmp(tname,typeid(std::vector<int>).name())) { + _wrt->insert(var.c_str(),att.c_str(), + dynamic_cast<MetaDataObject<std::vector<int> > * >(bs)->GetMetaDataObjectValue()); + } else if(!strcmp(tname,typeid(std::vector<short>).name())) { + _wrt->insert(var.c_str(),att.c_str(), + dynamic_cast<MetaDataObject<std::vector<short> > * >(bs)->GetMetaDataObjectValue()); + } else if(!strcmp(tname,typeid(std::vector<unsigned char>).name())) { + _wrt->insert(var.c_str(),att.c_str(), + dynamic_cast<MetaDataObject<std::vector<unsigned char> > * >(bs)->GetMetaDataObjectValue()); + } + } else if((*it).first=="history") { + itk::MetaDataObjectBase *bs=(*it).second; + _wrt->append_history(dynamic_cast<MetaDataObject<std::string> *>(bs)->GetMetaDataObjectValue().c_str()); + } + + } + } catch(const minc::generic_error & err) { + ExceptionObject exception(err.file(), err.line()); + std::string ErrorMessage="MINC IO error:"; + ErrorMessage+=err.msg(); + exception.SetDescription(ErrorMessage.c_str()); + throw exception; + } + return; + } + + void MincImageIO::Write( const void* buffer) + { + try + { + this->WriteImageInformation(); //Write the image Information before writing data + + switch(this->GetComponentType()) + { + case UCHAR: + case CHAR: + _wrt->setup_write_byte(false); + save_non_standard_volume<unsigned char>(*_wrt,(const unsigned char*)buffer); + break; + case SHORT: + _wrt->setup_write_short(); + save_non_standard_volume<short>(*_wrt,(const short*)buffer); + break; + case USHORT: + _wrt->setup_write_ushort(); + save_non_standard_volume<unsigned short>(*_wrt,(const unsigned short*)buffer); + break; + case INT: + _wrt->setup_write_int(); + save_non_standard_volume<int>(*_wrt,(const int*)buffer); + break; + case UINT: + _wrt->setup_write_uint(); + save_non_standard_volume<unsigned int>(*_wrt,(const unsigned int*)buffer); + break; + case FLOAT: + _wrt->setup_write_float(); + save_non_standard_volume<float>(*_wrt,(const float*)buffer); + break; + case DOUBLE: + _wrt->setup_write_double(); + save_non_standard_volume<double>(*_wrt,(const double*)buffer); + break; + default: + throw ExceptionObject(__FILE__,__LINE__,"Unsupported data type"); + } + //finish writing, cleanup + delete _wrt; + _wrt=NULL; + } catch(const minc::generic_error & err) { + throw ExceptionObject(__FILE__, __LINE__,"Error reading minc file"); + } + + } +} // end namespace itk
new file mode 100644 --- /dev/null +++ b/minc4itk/itkMincImageIO.h @@ -0,0 +1,99 @@ +/* ----------------------------- 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 __itkMincImageIO_h +#define __itkMincImageIO_h + +#ifdef _MSC_VER +#pragma warning ( disable : 4786 ) +#endif + +#include <itkImageIOBase.h> +#include <minc_1_simple.h> + +namespace itk +{ + + /** \class MincImageIO + * + * \author Vladimir S. Fonov + * \brief Class that defines how to read Minc file format. + * MINC IMAGE FILE FORMAT + * + * \ingroup IOFilters + */ + class ITK_EXPORT MincImageIO: public ImageIOBase + { + public: + /** Standard class typedefs. */ + typedef MincImageIO Self; + typedef ImageIOBase Superclass; + typedef SmartPointer<Self> Pointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(MincImageIO, Superclass); + + /*-------- This part of the interfaces deals with reading data. ----- */ + + /** Determine if the file can be read with this ImageIO implementation. + * \author Vladimir S. Fonov + * \param FileNameToRead The name of the file to test for reading. + * \post Sets classes ImageIOBase::m_FileName variable to be FileNameToWrite + * \return Returns true if this ImageIO can read the file specified. + */ + virtual bool CanReadFile(const char* FileNameToRead) ; + + /** Set the spacing and dimension information for the set filename. */ + virtual void ReadImageInformation(); + + /** Reads the data from disk into the memory buffer provided. */ + virtual void Read(void* buffer); + + /*-------- This part of the interfaces deals with writing data. ----- */ + + /** Determine if the file can be written with this ImageIO implementation. + * \param FileNameToWrite The name of the file to test for writing. + * \author Vladimir S. Fonov + * \post Sets classes ImageIOBase::m_FileName variable to be FileNameToWrite + * \return Returns true if this ImageIO can write the file specified. + */ + virtual bool CanWriteFile(const char * FileNameToWrite); + + /** Set the spacing and dimension information for the set filename. */ + virtual void WriteImageInformation(); + + /** Writes the data to disk from the memory buffer provided. */ + virtual void Write(const void* buffer); + + + protected: + //! minc 1 reader + minc::minc_1_reader *_rdr; + minc::minc_1_writer *_wrt; + MincImageIO(); + ~MincImageIO(); + void PrintSelf(std::ostream& os, Indent indent) const; + + MincImageIO(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + void clean(void); + }; +} // end namespace itk + +#endif // __itkMincImageIO_h
new file mode 100644 --- /dev/null +++ b/minc4itk/itkMincImageIOFactory.cxx @@ -0,0 +1,40 @@ +#include "itkMincImageIOFactory.h" +#include "itkCreateObjectFunction.h" +#include "itkMincImageIO.h" +#include <itkVersion.h> +#include <iostream> +namespace itk +{ + void MincImageIOFactory::PrintSelf(std::ostream&, Indent) const + { + + } + + + MincImageIOFactory::MincImageIOFactory() + { + this->RegisterOverride("itkImageIOBase", + "itkMincImageIO", + "Minc Image IO", + 1, + CreateObjectFunction<MincImageIO>::New()); + } + + MincImageIOFactory::~MincImageIOFactory() + { + } + + const char* + MincImageIOFactory::GetITKSourceVersion(void) const + { + return ITK_SOURCE_VERSION; + } + + const char* + MincImageIOFactory::GetDescription() const + { + return "Minc ImageIO Factory, allows the loading of Minc images into insight"; + } + +} // end namespace itk +
new file mode 100644 --- /dev/null +++ b/minc4itk/itkMincImageIOFactory.h @@ -0,0 +1,71 @@ +/* ----------------------------- 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 __itkMincImageIOFactory_h +#define __itkMincImageIOFactory_h + +#ifdef _MSC_VER +#pragma warning ( disable : 4786 ) +#endif + +#include "itkObjectFactoryBase.h" +#include "itkImageIOBase.h" + +namespace itk +{ +/** \class MincImageIOFactory + * \brief Create instances of MincImageIO objects using an object factory. + */ +class ITK_EXPORT MincImageIOFactory : public ObjectFactoryBase +{ +public: + /** Standard class typedefs. */ + typedef MincImageIOFactory Self; + typedef ObjectFactoryBase Superclass; + typedef SmartPointer<Self> Pointer; + typedef SmartPointer<const Self> ConstPointer; + + /** Class methods used to interface with the registered factories. */ + virtual const char* GetITKSourceVersion(void) const; + virtual const char* GetDescription(void) const; + + /** Method for class instantiation. */ + itkFactorylessNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(MincImageIOFactory, ObjectFactoryBase); + + /** Register one factory of this type */ + static void RegisterOneFactory(void) + { + MincImageIOFactory::Pointer metaFactory = MincImageIOFactory::New(); + ObjectFactoryBase::RegisterFactory(metaFactory); + } + +protected: + MincImageIOFactory(); + ~MincImageIOFactory(); + virtual void PrintSelf(std::ostream& os, Indent indent) const; + +private: + MincImageIOFactory(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + +}; + + +} // end namespace itk + +#endif
new file mode 100644 --- /dev/null +++ b/minc4itk/minc4itk_plugin.cxx @@ -0,0 +1,25 @@ +#include "itkMincImageIOFactory.h" + +#ifdef WIN32 +#define MyPlugin_EXPORT __declspec(dllexport) +#else +#define MyPlugin_EXPORT +#endif + +extern "C" { + MyPlugin_EXPORT itk::ObjectFactoryBase* itkLoad(); +} + +/** + * Routine that is called when the shared library is loaded by + * itk::ObjectFactoryBase::LoadDynamicFactories(). + * + * itkLoad() is C (not C++) function. + */ + +itk::ObjectFactoryBase* itkLoad() +{ + static itk::MincImageIOFactory::Pointer f=itk::MincImageIOFactory::New(); + return f; +} +
new file mode 100644 --- /dev/null +++ b/minc4itk/minc_general_transform.h @@ -0,0 +1,278 @@ +/* ----------------------------- 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 __MINC_GENERAL_TRANSFORM_H__ +#define __MINC_GENERAL_TRANSFORM_H__ + +#include <itkObject.h> +#include <itkPoint.h> +#include <itkVector.h> +#include <itkCovariantVector.h> +#include <vnl/vnl_matrix_fixed.h> +#include <vnl/vnl_vector_fixed.h> +#include <vnl/vnl_det.h> +#include <vnl/vnl_vector_fixed_ref.h> +#include <vnl/vnl_vector.h> + +#include <itkTransform.h> +#include <itkObjectFactory.h> + +//minc header +#include <volume_io.h> + +namespace minc +{ + /** \class XfmTransform + * \brief ITK wrapper around Minc general transform functions. + * + * \ingroup Transforms + * + */ + template < class TScalarType=double, unsigned int NInputDimensions=3,unsigned int NOutputDimensions=3> + class XfmTransform : public itk::Transform < TScalarType, NInputDimensions, NOutputDimensions> + { + public: + /** Standard class typedefs. */ + typedef XfmTransform Self; + typedef typename itk::Transform < TScalarType, NInputDimensions, NOutputDimensions> Superclass; + typedef typename itk::SmartPointer< Self > Pointer; + typedef typename itk::SmartPointer< const Self > ConstPointer; + + + /** New method for creating an object using a factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro( XfmTransform, itk::Transform ); + + /** Dimension of the domain space. */ + itkStaticConstMacro(InputSpaceDimension, unsigned int, NInputDimensions); + itkStaticConstMacro(OutputSpaceDimension, unsigned int, NOutputDimensions); + + /** Type of the input parameters. */ + + typedef double ScalarType; + + /** Type of the input parameters. */ + typedef typename Superclass::ParametersType ParametersType; + + /** Type of the Jacobian matrix. */ + typedef typename Superclass::JacobianType JacobianType; + + /** Standard vector type for this class. */ + typedef itk::Vector<TScalarType, + itkGetStaticConstMacro(InputSpaceDimension)> InputVectorType; + typedef itk::Vector<TScalarType, + itkGetStaticConstMacro(OutputSpaceDimension)> OutputVectorType; + + /** Standard covariant vector type for this class */ + typedef itk::CovariantVector<TScalarType, + itkGetStaticConstMacro(InputSpaceDimension)> InputCovariantVectorType; + + typedef itk::CovariantVector<TScalarType, + itkGetStaticConstMacro(OutputSpaceDimension)> OutputCovariantVectorType; + + /** Standard coordinate point type for this class */ + typedef itk::Point<TScalarType,NInputDimensions > InputPointType; + + typedef itk::Point<TScalarType,NInputDimensions > OutputPointType; + + /** Method to transform a point. */ + virtual OutputPointType TransformPoint(const InputPointType &point ) const + { + if(!_initialized) return point; + if(_invert && !_initialized_invert) return point; + OutputPointType pnt; + if(NInputDimensions==3 && NOutputDimensions==3) + general_transform_point((_invert ? &_xfm_inv : &_xfm), point[0], point[1], point[2],&pnt[0], &pnt[1], &pnt[2]); + else + itkExceptionMacro(<< "Sorry, only 3D to 3d minc xfm transform is currently implemented"); + return pnt; + } + //! use finate element difference to estimate local jacobian + void estimate_local_jacobian(const InputPointType &orig, vnl_matrix_fixed< double, 3, 3 > &m) + { + double u1,v1,w1; + double u2,v2,w2; + const double delta=1e-4; + + general_transform_point((_invert ? &_xfm_inv : &_xfm) , orig[0]-delta, orig[1], orig[2],&u1, &v1, &w1); + general_transform_point((_invert ? &_xfm_inv : &_xfm) , orig[0]+delta, orig[1], orig[2],&u2, &v2, &w2); + m(0,0)=(u2-u1)/(2*delta); + m(0,1)=(v2-v1)/(2*delta); + m(0,2)=(w2-w1)/(2*delta); + + general_transform_point((_invert ? &_xfm_inv : &_xfm) , orig[0], orig[1]-delta, orig[2],&u1, &v1, &w1); + general_transform_point((_invert ? &_xfm_inv : &_xfm) , orig[0], orig[1]+delta, orig[2],&u2, &v2, &w2); + m(1,0)=(u2-u1)/(2*delta); + m(1,1)=(v2-v1)/(2*delta); + m(1,2)=(w2-w1)/(2*delta); + + general_transform_point((_invert ? &_xfm_inv : &_xfm), orig[0], orig[1], orig[2]-delta,&u1, &v1, &w1); + general_transform_point((_invert ? &_xfm_inv : &_xfm), orig[0], orig[1], orig[2]+delta,&u2, &v2, &w2); + m(2,0)=(u2-u1)/(2*delta); + m(2,1)=(v2-v1)/(2*delta); + m(2,2)=(w2-w1)/(2*delta); + } + + /** Method to transform a vector. */ + virtual OutputVectorType TransformVector(const InputVectorType &vector) const + { + itkExceptionMacro( << "Not Implemented" ); + return vector; + } + + /** Method to transform a vnl_vector. */ +/* virtual OutputVnlVectorType TransformVector(const InputVnlVectorType &vector) const + { + itkExceptionMacro( << "Not Implemented" ); + return vector; + }*/ + + + /** Method to transform a CovariantVector. */ + virtual OutputCovariantVectorType TransformCovariantVector( + const InputCovariantVectorType &vector) const + { + itkExceptionMacro( << "Not Implemented" ); + return vector; + } + + + /** Set the transformation to an Identity + */ + virtual void SetIdentity( void ) + { + _cleanup(); + } + +#if ( ITK_VERSION_MAJOR > 3 ) + virtual void SetFixedParameters(const ParametersType &) + { + itkExceptionMacro( << "Not Implemented" ); + } + + virtual void ComputeJacobianWithRespectToParameters( + const InputPointType &, + JacobianType &) const + { + itkExceptionMacro( << "Not Implemented" ); + } + + virtual void ComputeJacobianWithRespectToPosition( + const InputPointType & x, + JacobianType &jacobian ) const + { + itkExceptionMacro( << "Not Implemented" ); + } + +#endif + + +#if ( ITK_VERSION_MAJOR > 3 ) + virtual NumberOfParametersType GetNumberOfParameters(void) const +#else + virtual unsigned int GetNumberOfParameters(void) const +#endif + { + //this transform is defined by XFM file + itkExceptionMacro( << "Not Defined" ); + return 0; + } + + /** Set the Transformation Parameters + * and update the internal transformation. */ + virtual void SetParameters(const ParametersType & param) + { + itkExceptionMacro( << "Not Implemented" ); + } + + virtual const ParametersType & GetParameters(void) + { + itkExceptionMacro( << "Not Implemented" ); + return _parameters; + } + +#if ( ITK_VERSION_MAJOR == 3 ) + virtual const JacobianType & GetJacobian(const InputPointType & point) const + { + itkExceptionMacro( << "Not Implemented" ); + return this->m_Jacobian; + } +#endif + + void OpenXfm(const char *xfm) + { + _cleanup(); + if(input_transform_file((char*)xfm, &_xfm)!=OK) + itkExceptionMacro( << "Error reading XFM:" << xfm ); + _initialized=true; + } + + void Invert(void) + { + if(!_initialized) + itkExceptionMacro( << "XFM not initialized" ); + if(!_initialized_invert) + { + create_inverse_general_transform(&_xfm,&_xfm_inv); + _initialized_invert=true; + } + _invert= !_invert; + } + + protected: + +#if ( ITK_VERSION_MAJOR > 3 ) + XfmTransform(): itk::Transform< TScalarType, NInputDimensions, NOutputDimensions>(0),_invert(false),_initialized(false),_initialized_invert(false) + { + } +#else + XfmTransform(): itk::Transform< TScalarType, NInputDimensions, NOutputDimensions>(NInputDimensions,NOutputDimensions),_invert(false),_initialized(false),_initialized_invert(false) + { + } +#endif + + virtual ~XfmTransform() + { + _cleanup(); + } + + void _cleanup(void) + { + if(_initialized) + { + delete_general_transform(&_xfm); + } + if(_initialized_invert) + { + delete_general_transform(&_xfm_inv); + } + _initialized=false; + _initialized_invert=false; + } + + ParametersType _parameters; + mutable General_transform _xfm,_xfm_inv;//quick fix for general_transform + bool _invert; + bool _initialized,_initialized_invert; + + private: + XfmTransform ( const Self & ); //purposely not implemented + void operator= ( const Self & ); //purposely not implemented + }; + + +}; +#endif //__MINC_GENERAL_TRANSFORM_H__
new file mode 100644 --- /dev/null +++ b/minc4itk/minc_helpers.cxx @@ -0,0 +1,778 @@ +/* ----------------------------- 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. +---------------------------------------------------------------------------- */ +#include <math.h> +#include "minc_helpers.h" + +#include <itkMetaDataObject.h> + +#include <iostream> +#include <fstream> +#include <sstream> +#include <iterator> + +using namespace std; + +namespace minc +{ + int get_image_limits (image3d::Pointer img, voxel_type &min,voxel_type &max) + { + //1. get min, max + minc::image3d_iterator it (img, img->GetLargestPossibleRegion ()); + int count = 0; + + min = std::numeric_limits < voxel_type >::max (); + + max = -std::numeric_limits < voxel_type >::max (); + for (it.GoToBegin (); !it.IsAtEnd (); ++it) + { + voxel_type v=it.Value (); + if (fabs(double(v)) > 1e20) + continue; + count++; + if (v < min) + min = v; + if (v > max) + max = v; + } + return count; + } + + int get_image_limits (mask3d::Pointer img, voxel_type &min,voxel_type &max) + { + //1. get min, max + minc::mask3d_iterator it (img, img->GetLargestPossibleRegion ()); + int count = 0; + + min = std::numeric_limits < voxel_type >::max (); + + max = -std::numeric_limits < voxel_type >::max (); + for (it.GoToBegin (); !it.IsAtEnd (); ++it) + { + voxel_type v=it.Value (); + if (fabs(double(v)) > 1e20) + continue; + count++; + if (v < min) + min = v; + if (v > max) + max = v; + } + return count; + } + + int get_image_limits (def3d::Pointer img, voxel_type &min, voxel_type &max) + { + //1. get min, max + minc::def3d_iterator it (img, img->GetLargestPossibleRegion ()); + int count = 0; + + min = std::numeric_limits < voxel_type >::max (); + max = -std::numeric_limits < voxel_type >::max (); + + for (it.GoToBegin (); !it.IsAtEnd (); ++it) + { + voxel_type va=v_max(it.Value () ); + voxel_type vi=v_min(it.Value () ); + if (fabs(double(va)) > 1e20) + continue; + count++; + if (vi < min) + min = vi; + if (va > max) + max = va; + } + return count; + } + + void normalize_mask(mask3d::Pointer img) + { + minc::mask3d_iterator it (img, img->GetLargestPossibleRegion ()); + for (it.GoToBegin (); !it.IsAtEnd (); ++it) + { + if(it.Value ()) it.Value ()=1; + } + } + + void write_tags(const tag_points& tags, const char * file) + { + std::ofstream out(file); + if(!out.good()) REPORT_ERROR("Can't open file!"); + out<<"MNI Tag Point File"<<std::endl; + out<<"Volumes = 1;"<<std::endl<<std::endl; + out<<"Points ="; + //TODO add all the things + for(tag_points::const_iterator i=tags.begin();i!=tags.end();i++) + { + out<<std::endl<<(*i)[0]<<" "<<(*i)[1]<< " "<<(*i)[2] <<" \"\""; + if(!out.good()) REPORT_ERROR("Can't write to file!"); + } + out << ";" << std::endl; + } + + void write_tags(const tag_points& tags,const std::vector<int>& labels, const char * file) + { + std::ofstream out(file); + if(!out.good()) REPORT_ERROR("Can't open file!"); + out<<"MNI Tag Point File"<<std::endl; + out<<"Volumes = 1;"<<std::endl<<std::endl; + out<<"Points ="; + //TODO add all the things + std::vector<int>::const_iterator j; + tag_points::const_iterator i; + for(i=tags.begin(),j=labels.begin();i!=tags.end()&&j!=labels.end();i++,j++) + { + out<<std::endl<<(*i)[0]<<" "<<(*i)[1]<< " "<<(*i)[2] <<" \""<<*j<<"\""; + if(!out.good()) REPORT_ERROR("Can't write to file!"); + } + out << ";" << std::endl; + } + + void write_tags(const tag_points& tags,const std::vector<float>& values, const char * file) + { + std::ofstream out(file); + if(!out.good()) REPORT_ERROR("Can't open file!"); + out<<"MNI Tag Point File"<<std::endl; + out<<"Volumes = 1;"<<std::endl<<std::endl; + out<<"Points ="; + //TODO add all the things + std::vector<float>::const_iterator j; + tag_points::const_iterator i; + for(i=tags.begin(),j=values.begin();i!=tags.end()&&j!=values.end();i++,j++) + { + out<<std::endl<<(*i)[0]<<" "<<(*i)[1]<< " "<<(*i)[2] <<" \""<<*j<<"\""; + if(!out.good()) REPORT_ERROR("Can't write to file!"); + } + out << ";" << std::endl; + + } + + void write_tags(const tag_points& tags,const std::vector<double>& values, const char * file) + { + std::ofstream out(file); + if(!out.good()) REPORT_ERROR("Can't open file!"); + out<<"MNI Tag Point File"<<std::endl; + out<<"Volumes = 1;"<<std::endl<<std::endl; + out<<"Points ="; + //TODO add all the things + std::vector<double>::const_iterator j; + tag_points::const_iterator i; + for(i=tags.begin(),j=values.begin();i!=tags.end()&&j!=values.end();i++,j++) + { + out<<std::endl<<(*i)[0]<<" "<<(*i)[1]<< " "<<(*i)[2] <<" \""<<*j<<"\""; + if(!out.good()) REPORT_ERROR("Can't write to file!"); + } + out << ";" << std::endl; + + } + + void write_2tags(const tag_points& tags,const tag_points& tags2, const char * file) + { + if(tags.size()!=tags2.size()) + REPORT_ERROR("Mismatching number of tags!"); + + std::ofstream out(file); + if(!out.good()) REPORT_ERROR("Can't open file!"); + out<<"MNI Tag Point File"<<std::endl; + out<<"Volumes = 2;"<<std::endl<<std::endl; + out<<"Points ="; + //TODO add all the things + tag_points::const_iterator j=tags2.begin(); + tag_points::const_iterator i=tags.begin(); + for(;i!=tags.end();i++,j++) + { + out<<std::endl<<(*i)[0]<<" "<<(*i)[1]<< " "<<(*i)[2]<<" "<<(*j)[0]<<" "<<(*j)[1]<< " "<<(*j)[2] <<" \"\""; + if(!out.good()) REPORT_ERROR("Can't write to file!"); + } + out << ";" << std::endl; + } + + static void split_string(char *str,std::vector<std::string>& lst,const char *delim=" ") + { + lst.clear(); + char *str2, *token; + char *saveptr; + while(str2=strtok_r(str,delim,&saveptr)) + { + str=NULL; + lst.push_back(str2); + } + } + + void read_tags(tag_points& tags, const char * file,int vol) + { + ifstream in(file); + if(!in.good()) REPORT_ERROR("Can't open file!"); + //tags.clear(); + bool seen_points=false; + const int _buffer_len=4095; + char tmp[_buffer_len+1]; + int _vol=vol; + + while(!in.eof() ) + { + in.getline(tmp,_buffer_len,'\n'); + if(tmp[0]=='%') continue; + if(!in.good()) break; + if(!seen_points) + { + if(!strncmp(tmp,"Volumes =",9)) //got number of volumes + { + char *del=strchr(tmp+9,';'); + if(del) *del=0; + _vol=atoi(tmp+9); + if(_vol<0 || _vol>2) _vol=1; + + } + + if(!strcmp(tmp,"Points =")) //found + { + seen_points=true; + continue; + } + } else { + std::istringstream str (std::string((const char *)tmp)); + tag_point tag; + double dummy; + + if(_vol>1 && vol>1) //skip extra values + str >> dummy >> dummy >> dummy; + + str>>tag[0]>>tag[1]>>tag[2]; + tags.push_back(tag); + } + } + } + + void read_tags(tag_points& tags, std::vector<int>& labels, const char * file, int vol) + { + ifstream in(file); + if(!in.good()) REPORT_ERROR("Can't open file!"); + //tags.clear(); + bool seen_points=false; + const int _buffer_len=4095; + char tmp[_buffer_len+1]; + int _vol=vol; + + while(!in.eof() ) + { + in.getline(tmp,_buffer_len,'\n'); + if(!in.good()) break; + if(tmp[0]=='%') continue; + + if(!seen_points) + { + if(!strncmp(tmp,"Volumes =",9)) //got number of volumes + { + char *del=strchr(tmp+9,';'); + if(del) *del=0; + _vol=atoi(tmp+9); + if(_vol<0 || _vol>2) _vol=1; + } + if(!strcmp(tmp,"Points =")) //found + { + seen_points=true; + continue; + } + } else { + std::vector<std::string> lst; + tag_point tag; + + split_string(tmp,lst," "); + int skip=0; + + if(lst.size()<3) continue; + + if(vol==2 && _vol==2 && lst.size()>5) //skip extra values + skip=3; + + tag[0]=atof(lst[skip].c_str()); + tag[1]=atof(lst[skip+1].c_str()); + tag[2]=atof(lst[skip+2].c_str()); + + tags.push_back(tag); + + if((lst.size()>6&&_vol==2) || lst.size()>3) + { + std::string lb=lst[lst.size()-1]; + + //Analyze label + std::string::size_type first=lb.find('"'); + std::string::size_type last=lb.rfind('"'); + if( first==std::string::npos || last==std::string::npos ) + labels.push_back(0); + else + labels.push_back(atoi(lb.substr(first+1,last-first).c_str())); + } else + labels.push_back(0); + } + } + } + + void read_tags(tag_points& tags, std::vector<double>& labels, const char * file, int vol) + { + ifstream in(file); + if(!in.good()) REPORT_ERROR("Can't open file!"); + //tags.clear(); + bool seen_points=false; + const int _buffer_len=4095; + char tmp[_buffer_len+1]; + int _vol=vol; + + while(!in.eof() ) + { + in.getline(tmp,_buffer_len,'\n'); + if(!in.good()) break; + if(tmp[0]=='%') continue; + + if(!seen_points) + { + if(!strncmp(tmp,"Volumes =",9)) //got number of volumes + { + char *del=strchr(tmp+9,';'); + if(del) *del=0; + _vol=atoi(tmp+9); + if(_vol<0 || _vol>2) _vol=1; + } + if(!strcmp(tmp,"Points =")) //found + { + seen_points=true; + continue; + } + } else { + std::vector<std::string> lst; + tag_point tag; + + split_string(tmp,lst," "); + int skip=0; + + if(lst.size()<3) continue; + + if(vol==2 && _vol==2 && lst.size()>5) //skip extra values + skip=3; + + tag[0]=atof(lst[skip].c_str()); + tag[1]=atof(lst[skip+1].c_str()); + tag[2]=atof(lst[skip+2].c_str()); + + tags.push_back(tag); + if((lst.size()>6&&_vol==2) || lst.size()>3) + { + std::string lb=lst[lst.size()-1]; + + std::string::size_type first=lb.find('"'); + std::string::size_type last=lb.rfind('"'); + if( first==std::string::npos || last==std::string::npos ) + labels.push_back(0); + else + labels.push_back(atof(lb.substr(first+1,last-first).c_str())); + } else + labels.push_back(0); + } + } + } + + void read_tags(tag_points& tags, std::vector<float>& labels, const char * file, int vol) + { + ifstream in(file); + if(!in.good()) REPORT_ERROR("Can't open file!"); + //tags.clear(); + bool seen_points=false; + const int _buffer_len=4095; + char tmp[_buffer_len+1]; + int _vol=vol; + + while(!in.eof() ) + { + in.getline(tmp,_buffer_len,'\n'); + if(!in.good()) break; + if(tmp[0]=='%') continue; + + if(!seen_points) + { + if(!strncmp(tmp,"Volumes =",9)) //got number of volumes + { + char *del=strchr(tmp+9,';'); + if(del) *del=0; + _vol=atoi(tmp+9); + if(_vol<0 || _vol>2) _vol=1; + } + if(!strcmp(tmp,"Points =")) //found + { + seen_points=true; + continue; + } + } else { + std::vector<std::string> lst; + tag_point tag; + + split_string(tmp,lst," "); + int skip=0; + + if(lst.size()<3) continue; + + if(vol==2 && _vol==2 && lst.size()>5) //skip extra values + skip=3; + + tag[0]=atof(lst[skip].c_str()); + tag[1]=atof(lst[skip+1].c_str()); + tag[2]=atof(lst[skip+2].c_str()); + + tags.push_back(tag); + if((lst.size()>6&&_vol==2) || lst.size()>3) + { + std::string lb=lst[lst.size()-1]; + + std::string::size_type first=lb.find('"'); + std::string::size_type last=lb.rfind('"'); + if( first==std::string::npos || last==std::string::npos ) + labels.push_back(0); + else + labels.push_back(atof(lb.substr(first+1,last-first).c_str())); + } else + labels.push_back(0); + } + } + } + + void read_tags(tag_points& tag1, tag_points& tag2,std::vector<double>& labels, const char * file) + { + ifstream in(file); + if(!in.good()) REPORT_ERROR("Can't open file!"); + //tags.clear(); + bool seen_points=false; + const int _buffer_len=4095; + char tmp[_buffer_len+1]; + int _vol=2; + + while(!in.eof() ) + { + in.getline(tmp,_buffer_len,'\n'); + if(!in.good()) break; + if(tmp[0]=='%') continue; + + if(!seen_points) + { + if(!strncmp(tmp,"Volumes =",9)) //got number of volumes + { + char *del=strchr(tmp+9,';'); + if(del) *del=0; + _vol=atoi(tmp+9); + if(_vol<0 || _vol>2) _vol=1; + } + if(!strcmp(tmp,"Points =")) //found + { + seen_points=true; + continue; + } + } else { + std::vector<std::string> lst; + tag_point tag; + + split_string(tmp,lst," "); + int skip=0; + + if(lst.size()<3) continue; + + tag[0]=atof(lst[0].c_str()); + tag[1]=atof(lst[1].c_str()); + tag[2]=atof(lst[2].c_str()); + tag1.push_back(tag); + + if(lst.size()>5 && _vol==2) + { + tag[0]=atof(lst[0].c_str()); + tag[1]=atof(lst[1].c_str()); + tag[2]=atof(lst[2].c_str()); + } else { + tag[0]=0; + tag[1]=0; + tag[2]=0; + } + tag2.push_back(tag); + + if((lst.size()>6&&_vol==2) || lst.size()>3) + { + std::string lb=lst[lst.size()-1]; + std::string::size_type first=lb.find('"'); + std::string::size_type last=lb.rfind('"'); + if( first==std::string::npos || last==std::string::npos ) + labels.push_back(0); + else + labels.push_back(atof(lb.substr(first+1,last-first).c_str())); + } else + labels.push_back(0); + } + } + } + + + void load_parameters(const char *file,itk::Array<double> ¶m) + { + std::vector<double> p; + ifstream in(file); + if(!in.good()) + REPORT_ERROR("Can't open the file for reading!"); + copy(istream_iterator<double>(in), istream_iterator<double>(), back_inserter(p)); + if(p.empty()) // probably this is not right! + REPORT_ERROR("Can't read parameters!"); + param.SetSize(p.size()); + for(int i=0;i<p.size();i++) + param[i]=p[i]; + } + + void load_parameters(const char *file,itk::Array<double> ¶m,int n) + { + std::vector<double> p; + ifstream in(file); + if(!in.good()) + REPORT_ERROR("Can't open the file for reading!"); + copy(istream_iterator<double>(in), istream_iterator<double>(), back_inserter(p)); + if(p.empty()) // probably this is not right! + REPORT_ERROR("Can't read parameters!"); + param.SetSize(n); + param.Fill(0); + + for(int i=0;i<p.size() && i<n;i++) + param[i]=p[i]; + } + + void save_parameters(const char *file,const itk::Array<double> ¶m) + { + std::vector<double> p; + ofstream out(file); + if(!out.good()) + REPORT_ERROR("Can't open the file for writing!"); + out.precision(40); + for(int i=0;i<param.Size();i++) + out<<param[i]<<endl; + } + + //simplistic XFM file parsing + void read_linear_xfm(const char *xfm,itk::Matrix<double,3,3>& rot, itk::Vector<double,3>& tran ) + { + rot.SetIdentity(); + tran.Fill(0); + std::ifstream in(xfm); + char tmp[1024]; + bool found_transform=false; + while(!in.eof() && in.good()) + { + in.getline(tmp,1023); + if(strstr(tmp,"Linear_Transform =")) // ok, found the description + { + found_transform=true; + break; + } + } + if(found_transform) + { + for(int c=0;c<3;c++) + { + in>>rot[c][0] + >>rot[c][1] + >>rot[c][2] + >>tran[c]; + } + } + } + + void read_linear_xfm(const char *xfm,itk::Matrix<double,2,2>& rot, itk::Vector<double,2>& tran ) + { + itk::Matrix<double,3,3> r; + itk::Vector<double,3> t; + read_linear_xfm(xfm,r,t); + + for(int i=0;i<2;i++) + { + for(int j=0;j<2;j++) + { + rot[i][j]=r[i][j]; + } + tran[i]=t[i]; + } + } + + + void write_linear_xfm(const char *xfm,const itk::Matrix<double,3,3>& rot,const itk::Vector<double,3>& tran ) + { + std::ofstream out(xfm); + out.precision(10); + out<<"MNI Transform File"<<std::endl; + out<<"Transform_Type = Linear;"<<std::endl<<"Linear_Transform ="; + for(int c=0;c<3;c++) + { + out<<std::endl<<rot[c][0]<<" " + <<rot[c][1]<<" " + <<rot[c][2]<<" " + <<tran[c]; + } + out<<";"<<std::endl; + } + + void write_linear_xfm(const char *xfm,const itk::Matrix<double,2,2>& rot,const itk::Vector<double,2>& tran ) + { + std::ofstream out(xfm); + out.precision(10); + out<<"MNI Transform File"<<std::endl; + out<<"Transform_Type = Linear;"<<std::endl<<"Linear_Transform ="; + for(int c=0;c<2;c++) + { + out<<std::endl<<rot[c][0]<<" " + <<rot[c][1]<<" " + <<0<<" " + <<tran[c]; + } + + out<<std::endl<<0<<" " + <<0<<" " + <<0<<" " + <<0; + + out<<";"<<std::endl; + } + + + void write_combined_xfm(const char *xfm,const itk::Matrix<double,3,3>& rot,const itk::Vector<double,3>& tran, const char *grid ) + { + std::ofstream out(xfm); + out.precision(10); + out<<"MNI Transform File"<<std::endl; + out<<"Transform_Type = Linear;"<<std::endl<<"Linear_Transform ="; + for(int c=0;c<3;c++) + { + out<<std::endl<<rot[c][0]<<" " + <<rot[c][1]<<" " + <<rot[c][2]<<" " + <<tran[c]; + } + out<<";"<<std::endl; + + out<<"Transform_Type = Grid_Transform;"<<std::endl<<"Displacement_Volume = "<<grid<<";"<<std::endl; + } + + void write_combined_xfm(const char *xfm,const itk::Matrix<double,2,2>& rot,const itk::Vector<double,2>& tran, const char *grid ) + { + std::ofstream out(xfm); + out.precision(10); + out<<"MNI Transform File"<<std::endl; + out<<"Transform_Type = Linear;"<<std::endl<<"Linear_Transform ="; + for(int c=0;c<2;c++) + { + out<<std::endl<<rot[c][0]<<" " + <<rot[c][1]<<" " + <<0<<" " + <<tran[c]; + } + + out<<std::endl<<0<<" " + <<0<<" " + <<0<<" " + <<0; + + out<<";"<<std::endl; + + out<<"Transform_Type = Grid_Transform;"<<std::endl<<"Displacement_Volume = "<<grid<<";"<<std::endl; + + } + + void write_combined_xfm(const char *xfm, const char *grid,const itk::Matrix<double,3,3>& rot,const itk::Vector<double,3>& tran) + { + std::ofstream out(xfm); + out.precision(10); + out<<"MNI Transform File"<<std::endl; + + out<<"Transform_Type = Grid_Transform;"<<std::endl<<"Displacement_Volume = "<<grid<<";"<<std::endl; + + out<<"Transform_Type = Linear;"<<std::endl<<"Linear_Transform ="; + for(int c=0;c<3;c++) + { + out<<std::endl<<rot[c][0]<<" " + <<rot[c][1]<<" " + <<rot[c][2]<<" " + <<tran[c]; + } + out<<";"<<std::endl; + } + + void write_combined_xfm(const char *xfm, const char *grid,const itk::Matrix<double,2,2>& rot,const itk::Vector<double,2>& tran ) + { + std::ofstream out(xfm); + out.precision(10); + out<<"MNI Transform File"<<std::endl; + + out<<"Transform_Type = Grid_Transform;"<<std::endl<<"Displacement_Volume = "<<grid<<";"<<std::endl; + + out<<"Transform_Type = Linear;"<<std::endl<<"Linear_Transform ="; + for(int c=0;c<2;c++) + { + out<<std::endl<<rot[c][0]<<" " + <<rot[c][1]<<" " + <<0<<" " + <<tran[c]; + } + + out<<std::endl<<0<<" " + <<0<<" " + <<0<<" " + <<0; + + out<<";"<<std::endl; + } + + void write_nonlinear_xfm(const char *xfm,const char *grid) + { + std::ofstream out(xfm); + out<<"MNI Transform File"<<std::endl; + out<<"Transform_Type = Linear;"<<std::endl<<"Linear_Transform ="; + for(int c=0;c<3;c++) + { + out<<std::endl<<(c==0?1:0)<<" " <<(c==1?1:0)<<" " <<(c==2?1:0)<<" " <<0; + } + out<<";"<<std::endl; + + out<<"Transform_Type = Grid_Transform;"<<std::endl<<" Displacement_Volume = "<<grid<<";"<<std::endl; + } + + void set_minc_storage_type(itk::Object* image,nc_type datatype,bool is_signed) + { + itk::EncapsulateMetaData( image->GetMetaDataDictionary(),"datatype",datatype); + itk::EncapsulateMetaData( image->GetMetaDataDictionary(),"signed",is_signed); + } + + void copy_metadata(itk::Object* dst,itk::Object* src) + { + dst->SetMetaDataDictionary(src->GetMetaDataDictionary()); + } + + void copy_dimorder(itk::Object* dst,itk::Object* src) + { + std::vector<std::string> dimorder; + if(itk::ExposeMetaData(src->GetMetaDataDictionary(),"dimorder",dimorder)) + { + itk::EncapsulateMetaData(dst->GetMetaDataDictionary(),"dimorder",dimorder); + } + } + + void append_history(itk::Object* dst,const std::string& history) + { + std::string old_history; + itk::ExposeMetaData<std::string>( dst->GetMetaDataDictionary() , "history",old_history); + old_history+=history; + itk::EncapsulateMetaData( dst->GetMetaDataDictionary(),"history",old_history); + } + + +};//minc +
new file mode 100644 --- /dev/null +++ b/minc4itk/minc_helpers.h @@ -0,0 +1,384 @@ +#ifndef _MINC_HELPERS_H_ +#define _MINC_HELPERS_H_ + +#include <complex> +#include <vector> +#include <algorithm> + +#include <itkArray.h> + +#if ( ITK_VERSION_MAJOR > 3 ) +#include <itkImage.h> +#else +#include <itkOrientedImage.h> +#endif + +#include <itkImageRegionIteratorWithIndex.h> +#include <itkImageRegionConstIteratorWithIndex.h> + +#include <itkImageFileReader.h> +#include <itkImageFileWriter.h> +#include <itkImageIOFactory.h> + +#include "itkMincImageIOFactory.h" +#include "itkMincImageIO.h" +#include <minc_io_fixed_vector.h> + +namespace minc +{ + + typedef unsigned char minc_mask_voxel; + + typedef float voxel_type; + const int volume_dimensions = 3; + + typedef itk::Vector<float,volume_dimensions> def_vector; + typedef itk::Point<double,volume_dimensions> tag_point; + typedef std::vector<tag_point> tag_points; + typedef std::complex < voxel_type > complex; + +#if ( ITK_VERSION_MAJOR > 3 ) + typedef itk::Image < complex, volume_dimensions > image3d_complex; + typedef itk::Image < voxel_type, volume_dimensions > image3d; + typedef itk::Image < minc_mask_voxel, volume_dimensions > mask3d; + typedef itk::Image < def_vector, volume_dimensions > def3d; +#else + typedef itk::OrientedImage < complex, volume_dimensions > image3d_complex; + typedef itk::OrientedImage < voxel_type, volume_dimensions > image3d; + typedef itk::OrientedImage < minc_mask_voxel, volume_dimensions > mask3d; + typedef itk::OrientedImage < def_vector, volume_dimensions > def3d; +#endif + + + + typedef itk::ImageRegionIteratorWithIndex < image3d > image3d_iterator; + typedef itk::ImageRegionConstIteratorWithIndex < image3d > image3d_const_iterator; + + typedef itk::ImageRegionIteratorWithIndex < mask3d > mask3d_iterator; + typedef itk::ImageRegionConstIteratorWithIndex < mask3d > mask3d_const_iterator; + + typedef itk::ImageRegionIteratorWithIndex < def3d > def3d_iterator; + typedef itk::ImageRegionConstIteratorWithIndex < def3d > def3d_const_iterator; + + typedef itk::ImageRegionIteratorWithIndex < image3d_complex > image3d_complex_iterator; + typedef itk::ImageRegionConstIteratorWithIndex < image3d_complex > image3d_complex_const_iterator; + + //! find a maximum of elements + template<class T> float v_max(const T& c) + { + float s=std::numeric_limits < float >::min ();; + for(unsigned int i=0;i<3;i++) + if(c[i]>s) s=c[i]; + return s; + } + + //! find a minimum of elements + template<class T> float v_min(const T& c) + { + float s=std::numeric_limits < float >::max ();; + for(unsigned int i=0;i<3;i++) + if(c[i]<s) s=c[i]; + return s; + } + + //! allocate volume of the same dimension,spacing and origin + template<class T,class S> void allocate_same(typename T::Pointer &image,const typename S::Pointer &sample) + { + image->SetLargestPossibleRegion(sample->GetLargestPossibleRegion()); + image->SetBufferedRegion(sample->GetLargestPossibleRegion()); + image->SetRequestedRegion(sample->GetLargestPossibleRegion()); + image->SetSpacing( sample->GetSpacing() ); + image->SetOrigin ( sample->GetOrigin() ); + image->SetDirection(sample->GetDirection()); + image->Allocate(); + } + + //! allocate volume of the same dimension,spacing and origin + template<class T,class S> void allocate_same(typename T::Pointer &image,const typename S::ConstPointer &sample) + { + image->SetLargestPossibleRegion(sample->GetLargestPossibleRegion()); + image->SetBufferedRegion(sample->GetLargestPossibleRegion()); + image->SetRequestedRegion(sample->GetLargestPossibleRegion()); + image->SetSpacing( sample->GetSpacing() ); + image->SetOrigin ( sample->GetOrigin() ); + image->SetDirection(sample->GetDirection()); + image->Allocate(); + } + + + + //! allocate volume of the same dimension,spacing and origin + template<class T,class S> typename T::Pointer allocate_same(const typename S::Pointer &sample) + { + typename T::Pointer image=T::New(); + image->SetLargestPossibleRegion(sample->GetLargestPossibleRegion()); + image->SetBufferedRegion(sample->GetLargestPossibleRegion()); + image->SetRequestedRegion(sample->GetLargestPossibleRegion()); + image->SetSpacing( sample->GetSpacing() ); + image->SetOrigin ( sample->GetOrigin() ); + image->SetDirection(sample->GetDirection()); + image->Allocate(); + return image; + } + + + //! allocate volume of the same dimension,spacing and origin and do nearest neighbour resampling + template<class T,class S,class E,class D> void nearest_resample_like(typename T::Pointer &dst,const typename S::Pointer &sample,const typename E::Pointer &src, const D& def) + { + allocate_same<T,S>(dst,sample); + itk::ImageRegionIteratorWithIndex<T> it(dst, dst->GetLargestPossibleRegion()); + for(it.GoToBegin(); !it.IsAtEnd(); ++it) + { + tag_point p; + typename E::IndexType idx; + dst->TransformIndexToPhysicalPoint(it.GetIndex(),p); + if(src->TransformPhysicalPointToIndex(p,idx)) + { + it.Value()=src->GetPixel(idx); + }else{ + it.Value()=def; + } + } + } + + //! check if volumes have the same dimensions, spacing and origin + template<class T,class S> bool check_same(typename T::Pointer image,typename S::Pointer sample) + { + return + (image->GetLargestPossibleRegion() == sample->GetLargestPossibleRegion()) && + (image->GetSpacing() == sample->GetSpacing()) && + (image->GetOrigin() == sample->GetOrigin()) && + (image->GetDirection().GetVnlMatrix() == sample->GetDirection().GetVnlMatrix()); // carefull here! , maybe we should calculate some kind of difference here ? + // this is warkaround a bug in itk + } + + //! allocate volume + //! \param[out] image - volume to allocate + //! \param dims - dimensions (voxels) + //! \param spacing - volume spacing (mm) + //! \param origin - volume origin (mm) + template<class T> void allocate_image3d(typename T::Pointer &image, + const itk::Array<unsigned int> &dims, + const itk::Array<double>& spacing, + const itk::Array<double>& origin) + { + image3d_complex::SizeType imageSize3D = {{ dims[0], dims[1], dims[2]}}; + image3d_complex::IndexType startIndex3D = { {0, 0, 0}}; + image3d_complex::RegionType region; + region.SetSize (imageSize3D); + region.SetIndex (startIndex3D); + image->SetLargestPossibleRegion (region); + image->SetBufferedRegion (region); + image->SetRequestedRegion (region); + image->SetSpacing( spacing ); + image->SetOrigin( origin ); + image->Allocate (); + } + + //! allocate volume + //! \param[out] image - volume to allocate + //! \param dims - dimensions (voxels) + //! \param spacing - volume spacing (mm) + //! \param origin - volume origin (mm) + template<class T> void allocate_image3d(typename T::Pointer &image, + const itk::Vector<unsigned int,3> &dims, + const itk::Vector<double,3>& spacing, + const itk::Vector<double,3>& origin) + { + image3d_complex::SizeType imageSize3D = {{ dims[0], dims[1], dims[2]}}; + image3d_complex::IndexType startIndex3D = { {0, 0, 0}}; + image3d_complex::RegionType region; + region.SetSize (imageSize3D); + region.SetIndex (startIndex3D); + image->SetLargestPossibleRegion (region); + image->SetBufferedRegion (region); + image->SetRequestedRegion (region); + image->SetSpacing( spacing ); + image->SetOrigin( origin.GetDataPointer () ); + image->Allocate (); + } + + //! allocate volume + //! \param[out] image - volume to allocate + //! \param dims - dimensions (voxels) + //! \param spacing - volume spacing (mm) + //! \param origin - volume origin (mm) + template<class T> void allocate_image3d(typename T::Pointer &image, + const fixed_vec<3, unsigned int>&dims, + const fixed_vec<3, double>& spacing=fixed_vec<3, double>(1.0) , + const fixed_vec<3, double>& origin=fixed_vec<3, double>(0.0)) + { + image3d_complex::SizeType imageSize3D = {{ dims[0], dims[1], dims[2]}}; + image3d_complex::IndexType startIndex3D = { {0, 0, 0}}; + image3d_complex::RegionType region; + region.SetSize (imageSize3D); + region.SetIndex (startIndex3D); + image->SetLargestPossibleRegion (region); + image->SetBufferedRegion (region); + image->SetRequestedRegion (region); + image->SetSpacing( spacing.c_buf() ); + image->SetOrigin( origin.c_buf() ); + image->Allocate (); + } + + + inline image3d::SizeType operator/= (image3d::SizeType & s, int d) + { + s[0] /= d; + s[1] /= d; + s[2] /= d; + return s; + } + + inline image3d::SizeType operator*= (image3d::SizeType & s, int d) + { + s[0] *= d; + s[1] *= d; + s[2] *= d; + return s; + } + +// a helper function for minc reading + template <class T> typename T::Pointer load_minc(const char *file) + { + typedef itk::MincImageIO ImageIOType; + ImageIOType::Pointer minc2ImageIO = ImageIOType::New(); + + typename itk::ImageFileReader<T>::Pointer reader = itk::ImageFileReader<T>::New(); + + reader->SetFileName(file); + reader->SetImageIO( minc2ImageIO ); + reader->Update(); + + return reader->GetOutput(); + } + + + void set_minc_storage_type(itk::Object* image,nc_type datatype,bool is_signed); + void copy_metadata(itk::Object* dst,itk::Object* src); + void copy_dimorder(itk::Object* dst,itk::Object* src); + void append_history(itk::Object* dst,const std::string& history); + + // a helper function for minc writing + template <class T> void save_minc(const char *file,typename T::Pointer img) + { + typedef itk::MincImageIO ImageIOType; + ImageIOType::Pointer minc2ImageIO = ImageIOType::New(); + + typename itk::ImageFileWriter< T >::Pointer writer = itk::ImageFileWriter<T>::New(); + writer->SetFileName(file); + writer->SetImageIO( minc2ImageIO ); + writer->SetInput( img ); + writer->Update(); + } + + //! allocate volume with spacing 1mm and origin 0,0,0 + //! \param[out] image - volume to allocate + //! \param dims - dimensions (voxels) + template<class T> void allocate_image3d(typename T::Pointer &image, const itk::Size<3> &dims) + { + allocate_image3d<T>(image,IDX<unsigned int>(dims[0],dims[1],dims[2])); + } + + //! calculate volume min and max + int get_image_limits(image3d::Pointer, voxel_type &min, voxel_type &max); + //! calculate volume min and max + int get_image_limits(def3d::Pointer, voxel_type &min, voxel_type &max); + //! calculate volume min and max + int get_image_limits(mask3d::Pointer img, voxel_type &min,voxel_type &max); + + //! store tags to minc tags file + void write_tags(const tag_points& tags, const char * file); + //! store two sets of tags to minc tags file + void write_2tags(const tag_points& tags,const tag_points& tags2, const char * file); + + //! store tags and labels + void write_tags(const tag_points& tags,const std::vector<int>& labels, const char * file); + //! store tags and values + void write_tags(const tag_points& tags,const std::vector<float>& values, const char * file); + //! store tags and values + void write_tags(const tag_points& tags,const std::vector<double>& values, const char * file); + + + //! read tags from the minc tag file + void read_tags(tag_points& tags, const char * file,int vol=1); + + //! read tags and labels from minc tag file + void read_tags(tag_points& tags, std::vector<int>& labels, const char * file, int vol=1); + + //! read tags and labels from minc tag file + void read_tags(tag_points& tags, std::vector<float>& labels, const char * file, int vol=1); + + //! read tags and labels from minc tag file + void read_tags(tag_points& tags, std::vector<double>& labels, const char * file, int vol=1); + + //! read tags and labels from minc tag file + void read_tags(tag_points& tag1, tag_points& tag2,std::vector<double>& labels, const char * file); + + + //! read array from the text file + void load_parameters(const char *file,itk::Array<double> ¶m); + //! save array to the text file + void save_parameters(const char *file,const itk::Array<double> ¶m); + //! read array from the text file, up to components + void load_parameters(const char *file,itk::Array<double> ¶m,int no); + //! make sure that all voxels are 0 or 1 + void normalize_mask(mask3d::Pointer img); + + void read_linear_xfm(const char *xfm,itk::Matrix<double,3,3>& rot, itk::Vector<double,3>& tran ); + void read_linear_xfm(const char *xfm,itk::Matrix<double,2,2>& rot, itk::Vector<double,2>& tran ); + + void write_linear_xfm(const char *xfm,const itk::Matrix<double,3,3>& rot,const itk::Vector<double,3>& tran); + void write_linear_xfm(const char *xfm,const itk::Matrix<double,2,2>& rot,const itk::Vector<double,2>& tran); + + void write_combined_xfm(const char *xfm,const itk::Matrix<double,3,3>& rot,const itk::Vector<double,3>& tran, const char *grid ); + void write_combined_xfm(const char *xfm,const itk::Matrix<double,2,2>& rot,const itk::Vector<double,2>& tran, const char *grid ); + + void write_combined_xfm(const char *xfm,const char *grid, const itk::Matrix<double,3,3>& rot,const itk::Vector<double,3>& tran ); + void write_combined_xfm(const char *xfm,const char *grid, const itk::Matrix<double,2,2>& rot,const itk::Vector<double,2>& tran ); + + void write_nonlinear_xfm(const char *xfm,const char *grid); + + //! minc4itk compatibility function + template <class T> void load_minc(const char *file,typename T::Pointer& img) + { + img=load_minc<T>(file); + } + + template<class T> void setup_itk_image(const minc_1_base& minc_rw, typename T::Pointer& img) + { + itk::Vector< unsigned int,3> dims; + itk::Vector< double,3> spacing; + itk::Vector< double,3> origin; + itk::Vector< double,3> start; + itk::Matrix< double, 3, 3> dir_cos; + dir_cos.SetIdentity(); + //std::cout<<"setup_itk_image"<<std::endl; + for(int i=0;i<3;i++) + { + dims[i]=minc_rw.ndim(i+1); + spacing[i]=minc_rw.nspacing(i+1); + start[i]=minc_rw.nstart(i+1); + if(minc_rw.have_dir_cos(i+1)) + { + for(int j=0;j<3;j++) + dir_cos[j][i]=minc_rw.ndir_cos(i+1,j); //TODO: check transpose? + } + //std::cout<<start[i]<<"\t"; + } + //std::cout<<std::endl; + origin=dir_cos*start; + allocate_image3d<T>(img,dims,spacing,origin); + img->SetDirection(dir_cos); + } + + template<class T> void imitate_minc (const char *path, typename T::Pointer &img) + { + minc_1_reader rdr; + rdr.open(path,true,true); + setup_itk_image<T>(rdr,img); + } + +}; + +#endif //_MINC_HELPERS_H_
--- a/progs/CMakeLists.txt +++ b/progs/CMakeLists.txt @@ -2,137 +2,163 @@ # # Andrew Janke - a.janke@gmail.com -#SET(CMAKE_MODULE_PATH "../cmake-modules") +#SET(CMAKE_MODULE_PATH "cmake-modules") -LINK_DIRECTORIES(../) +#LINK_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/..) INCLUDE_DIRECTORIES(Proglib) -LINK_LIBRARIES( minc2 ${NETCDF_LIBRARY} ${HDF5_LIBRARY} ) + +LINK_LIBRARIES( ${minc_LIB} ) ADD_DEFINITIONS(-DHAVE_CONFIG_H) -SET(BISON_FIND_REQUIRED) -SET(FLEX_FIND_REQUIRED) +#SET(BISON_FIND_REQUIRED) +#SET(FLEX_FIND_REQUIRED) + FIND_PACKAGE(BISON) FIND_PACKAGE(FLEX) # all the progs -ADD_EXECUTABLE(../invert_raw_image mincview/invert_raw_image.c) -ADD_EXECUTABLE(../mincaverage mincaverage/mincaverage.c) +ADD_EXECUTABLE(invert_raw_image mincview/invert_raw_image.c) +ADD_EXECUTABLE(mincaverage mincaverage/mincaverage.c) + +IF(BISON_FOUND AND FLEX_FOUND) + include_directories(${CMAKE_CURRENT_BINARY_DIR} minccalc) + + BISON_TARGET(gram ${CMAKE_CURRENT_SOURCE_DIR}/minccalc/gram.y ${CMAKE_CURRENT_BINARY_DIR}/gram.c COMPILE_FLAGS "--debug") + FLEX_TARGET(lex ${CMAKE_CURRENT_SOURCE_DIR}/minccalc/lex.l ${CMAKE_CURRENT_BINARY_DIR}/lex.c ) + #ADD_FLEX_BISON_DEPENDENCY(gram lex) + + ADD_EXECUTABLE(minccalc + minccalc/minccalc.c + minccalc/eval.c + minccalc/ident.c + minccalc/node.c + minccalc/optim.c + minccalc/scalar.c + minccalc/sym.c + minccalc/vector.c + ${FLEX_lex_OUTPUTS} + ${BISON_gram_OUTPUTS} + ) + + TARGET_LINK_LIBRARIES(minccalc ${FLEX_LIBRARIES}) -BISON_TARGET(../minccalc minccalc/gram.y minccalc/gram.c COMPILE_FLAGS "--debug") -FLEX_TARGET(../minccalc minccalc/lex.l minccalc/lex.c) -ADD_EXECUTABLE(../minccalc minccalc/minccalc.c - minccalc/gram.c - minccalc/eval.c - minccalc/ident.c - minccalc/lex.c - minccalc/node.c - minccalc/optim.c - minccalc/scalar.c - minccalc/sym.c - minccalc/vector.c) + INSTALL( TARGETS minccalc DESTINATION bin) + + include_directories(${CMAKE_CURRENT_BINARY_DIR} mincgen) + BISON_TARGET(ncgentab ${CMAKE_CURRENT_SOURCE_DIR}/mincgen/ncgentab.y ${CMAKE_CURRENT_BINARY_DIR}/ncgentab.c) + FLEX_TARGET(ncgenyy ${CMAKE_CURRENT_SOURCE_DIR}/mincgen/ncgenyy.l ${CMAKE_CURRENT_BINARY_DIR}/ncgenyy.c) + #ADD_FLEX_BISON_DEPENDENCY(ncgenyy ncgentab) -ADD_EXECUTABLE(../mincconcat mincconcat/mincconcat.c) -ADD_EXECUTABLE(../mincconvert mincconvert/mincconvert.c) -ADD_EXECUTABLE(../minccopy minccopy/minccopy.c) + ADD_EXECUTABLE(mincgen mincgen/main.c + ${BISON_ncgentab_OUTPUTS} + ${FLEX_ncgenyy_OUTPUTS} + mincgen/escapes.c + mincgen/genlib.c + mincgen/getfill.c + mincgen/init.c + mincgen/load.c) + INSTALL( TARGETS mincgen DESTINATION bin) -ADD_EXECUTABLE(../mincdump mincdump/mincdump.c + TARGET_LINK_LIBRARIES(mincgen ${FLEX_LIBRARIES}) + +ENDIF(BISON_FOUND AND FLEX_FOUND) + +ADD_EXECUTABLE(mincconcat mincconcat/mincconcat.c) +ADD_EXECUTABLE(mincconvert mincconvert/mincconvert.c) +ADD_EXECUTABLE(minccopy minccopy/minccopy.c) + +ADD_EXECUTABLE(mincdump mincdump/mincdump.c mincdump/vardata.c mincdump/dumplib.c) -ADD_EXECUTABLE(../mincexample1 mincexample/mincexample1.c) -ADD_EXECUTABLE(../mincexample2 mincexample/mincexample2.c) -ADD_EXECUTABLE(../mincexpand mincexpand/mincexpand.c) -ADD_EXECUTABLE(../mincextract mincextract/mincextract.c) +ADD_EXECUTABLE(mincexample1 mincexample/mincexample1.c) +ADD_EXECUTABLE(mincexample2 mincexample/mincexample2.c) +ADD_EXECUTABLE(mincexpand mincexpand/mincexpand.c) +ADD_EXECUTABLE(mincextract mincextract/mincextract.c) +ADD_EXECUTABLE(mincinfo mincinfo/mincinfo.c) +ADD_EXECUTABLE(minclookup minclookup/minclookup.c) +ADD_EXECUTABLE(mincmakescalar mincmakescalar/mincmakescalar.c) +ADD_EXECUTABLE(mincmakevector mincmakevector/mincmakevector.c) +ADD_EXECUTABLE(mincmath mincmath/mincmath.c) +ADD_EXECUTABLE(minc_modify_header minc_modify_header/minc_modify_header.c) -BISON_TARGET(../mincgen mincgen/ncgentab.y mincgen/nccentab.c) -FLEX_TARGET(../mincgen mincgen/ncgenyy.l mincgen/ncgenyy.c) -ADD_EXECUTABLE(../mincgen mincgen/main.c - mincgen/escapes.c - mincgen/genlib.c - mincgen/getfill.c - mincgen/init.c - mincgen/load.c - mincgen/ncgentab.c - mincgen/ncgenyy.c) - -ADD_EXECUTABLE(../mincinfo mincinfo/mincinfo.c) -ADD_EXECUTABLE(../minclookup minclookup/minclookup.c) -ADD_EXECUTABLE(../mincmakescalar mincmakescalar/mincmakescalar.c) -ADD_EXECUTABLE(../mincmakevector mincmakevector/mincmakevector.c) -ADD_EXECUTABLE(../mincmath mincmath/mincmath.c) -ADD_EXECUTABLE(../minc_modify_header minc_modify_header/minc_modify_header.c) - -ADD_EXECUTABLE(../mincresample mincresample/mincresample.c +ADD_EXECUTABLE(mincresample mincresample/mincresample.c mincresample/resample_volumes.c Proglib/convert_origin_to_start.c) -TARGET_LINK_LIBRARIES(../mincresample volume_io2) +TARGET_LINK_LIBRARIES(mincresample ${volume_io_LIB} ${minc_LIB}) -ADD_EXECUTABLE(../mincreshape mincreshape/mincreshape.c +ADD_EXECUTABLE(mincreshape mincreshape/mincreshape.c mincreshape/copy_data.c) -ADD_EXECUTABLE(../mincstats mincstats/mincstats.c) -ADD_EXECUTABLE(../minctoraw minctoraw/minctoraw.c) -ADD_EXECUTABLE(../mincwindow mincwindow/mincwindow.c) +ADD_EXECUTABLE(mincstats mincstats/mincstats.c) +ADD_EXECUTABLE(minctoraw minctoraw/minctoraw.c) +ADD_EXECUTABLE(mincwindow mincwindow/mincwindow.c) -ADD_EXECUTABLE(../rawtominc rawtominc/rawtominc.c +ADD_EXECUTABLE(rawtominc rawtominc/rawtominc.c Proglib/convert_origin_to_start.c) -ADD_EXECUTABLE(../voxeltoworld coordinates/voxeltoworld.c) -TARGET_LINK_LIBRARIES(../voxeltoworld volume_io2 minc2) +ADD_EXECUTABLE(voxeltoworld coordinates/voxeltoworld.c) +TARGET_LINK_LIBRARIES(voxeltoworld ${volume_io_LIB} ${minc_LIB}) -ADD_EXECUTABLE(../worldtovoxel coordinates/worldtovoxel.c) -TARGET_LINK_LIBRARIES(../worldtovoxel volume_io2 minc2) +ADD_EXECUTABLE(worldtovoxel coordinates/worldtovoxel.c) +TARGET_LINK_LIBRARIES(worldtovoxel ${volume_io_LIB} ${minc_LIB}) -ADD_EXECUTABLE(../transformtags xfm/transformtags.c) -TARGET_LINK_LIBRARIES(../transformtags volume_io2 minc2) +ADD_EXECUTABLE(transformtags xfm/transformtags.c) +TARGET_LINK_LIBRARIES(transformtags ${volume_io_LIB} ${minc_LIB}) -ADD_EXECUTABLE(../xfmconcat xfm/xfmconcat.c) -TARGET_LINK_LIBRARIES(../xfmconcat volume_io2 minc2) +ADD_EXECUTABLE(xfmconcat xfm/xfmconcat.c) +TARGET_LINK_LIBRARIES(xfmconcat ${volume_io_LIB} ${minc_LIB}) -ADD_EXECUTABLE(../xfminvert xfm/xfminvert.c) -TARGET_LINK_LIBRARIES(../xfminvert volume_io2 minc2) +ADD_EXECUTABLE(xfminvert xfm/xfminvert.c) +TARGET_LINK_LIBRARIES(xfminvert ${volume_io_LIB} ${minc_LIB}) # install progs INSTALL(TARGETS - ../invert_raw_image - ../mincaverage - ../minccalc - ../mincconcat - ../mincconvert - ../minccopy - ../mincdump -# ../mincexample1 -# ../mincexample2 - ../mincexpand - ../mincextract - ../mincgen - ../mincinfo - ../minclookup - ../mincmakescalar - ../mincmakevector - ../mincmath - ../minc_modify_header - ../mincresample - ../mincreshape - ../mincstats - ../minctoraw - ../mincwindow - ../rawtominc - ../voxeltoworld - ../worldtovoxel - ../transformtags - ../xfmconcat - ../xfminvert + invert_raw_image + mincaverage + mincconcat + mincconvert + minccopy + mincdump +# mincexample1 +# mincexample2 + mincexpand + mincextract + mincinfo + minclookup + mincmakescalar + mincmakevector + mincmath + minc_modify_header + mincresample + mincreshape + mincstats + minctoraw + mincwindow + rawtominc + voxeltoworld + worldtovoxel + transformtags + xfmconcat + xfminvert DESTINATION bin) - # perl and shell scripts INSTALL(FILES mincdiff/mincdiff mincedit/mincedit mincheader/mincheader - minchistory/minchistory mincpik/mincpik mincview/mincview + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ DESTINATION bin ) + + +configure_file(minchistory/minchistory.in ${CMAKE_CURRENT_BINARY_DIR}/minchistory @ONLY) +add_custom_target(minchistory chmod +x ${CMAKE_CURRENT_BINARY_DIR}/minchistory DEPENDS minchistory/minchistory.in) + +INSTALL(FILES + ${CMAKE_CURRENT_BINARY_DIR}/minchistory + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ + DESTINATION bin )
--- a/progs/minccalc/eval.c +++ b/progs/minccalc/eval.c @@ -20,7 +20,7 @@ scalar_t eval_index(int, int *, node_t, vector_t, scalar_t); scalar_t eval_sum(int, int *, node_t, vector_t); scalar_t eval_prod(int, int *, node_t, vector_t); -scalar_t eval_max(int, int *, node_t, vector_t, double); +scalar_t eval_max(int, int *, node_t, vector_t, double, int); vector_t eval_vector(int, int *, node_t, sym_t); vector_t gen_vector(int, int *, node_t, sym_t); vector_t gen_range(int, int *, node_t, sym_t); @@ -315,13 +315,25 @@ case NODETYPE_MAX: v = eval_vector(width, eval_flags, n->expr[0], sym); - s = eval_max(width, eval_flags, n, v, 1.0); + s = eval_max(width, eval_flags, n, v, 1.0, 0); vector_free(v); return s; case NODETYPE_MIN: v = eval_vector(width, eval_flags, n->expr[0], sym); - s = eval_max(width, eval_flags, n, v, -1.0); + s = eval_max(width, eval_flags, n, v, -1.0, 0); + vector_free(v); + return s; + + case NODETYPE_IMAX: + v = eval_vector(width, eval_flags, n->expr[0], sym); + s = eval_max(width, eval_flags, n, v, 1.0, 1); + vector_free(v); + return s; + + case NODETYPE_IMIN: + v = eval_vector(width, eval_flags, n->expr[0], sym); + s = eval_max(width, eval_flags, n, v, -1.0, 1); vector_free(v); return s; @@ -532,27 +544,29 @@ } /* Find the maximum of a vector. Sign should be +1.0 for maxima search - and -1.0 for minima search */ + and -1.0 for minima search. + type should be 0 for value and 1 for index */ scalar_t eval_max(int width, int *eval_flags, - node_t n, vector_t v, double sign) + node_t n, vector_t v, double sign, int type) { int i, ivalue; scalar_t result; - double value, ans; + double value, max, idx; result = new_scalar(width); for (ivalue=0; ivalue < width; ivalue++) { if (eval_flags != NULL && !eval_flags[ivalue]) continue; - result->vals[ivalue] = ans = INVALID_VALUE; + result->vals[ivalue] = max = INVALID_VALUE; for (i = 0; i < v->len; i++) { value = v->el[i]->vals[ivalue]; if (value != INVALID_VALUE) { - if (ans == INVALID_VALUE || (sign*(value-ans) > 0.0)) { - ans = value; + if (max == INVALID_VALUE || (sign*(value-max) > 0.0)) { + max = value; + idx = (double)i; } } } - result->vals[ivalue] = ans; + result->vals[ivalue] = (type == 0) ? max : idx; } return result; }
--- a/progs/minccalc/gram.c +++ b/progs/minccalc/gram.c @@ -124,31 +124,33 @@ LEN = 268, MAX = 269, MIN = 270, - ISNAN = 271, - SQRT = 272, - ABS = 273, - EXP = 274, - LOG = 275, - SIN = 276, - COS = 277, - TAN = 278, - ASIN = 279, - ACOS = 280, - ATAN = 281, - CLAMP = 282, - SEGMENT = 283, - LT = 284, - LE = 285, - GT = 286, - GE = 287, - EQ = 288, - NE = 289, - NOT = 290, - AND = 291, - OR = 292, - IF = 293, - ELSE = 294, - FOR = 295 + IMAX = 271, + IMIN = 272, + ISNAN = 273, + SQRT = 274, + ABS = 275, + EXP = 276, + LOG = 277, + SIN = 278, + COS = 279, + TAN = 280, + ASIN = 281, + ACOS = 282, + ATAN = 283, + CLAMP = 284, + SEGMENT = 285, + LT = 286, + LE = 287, + GT = 288, + GE = 289, + EQ = 290, + NE = 291, + NOT = 292, + AND = 293, + OR = 294, + IF = 295, + ELSE = 296, + FOR = 297 }; #endif /* Tokens. */ @@ -165,31 +167,33 @@ #define LEN 268 #define MAX 269 #define MIN 270 -#define ISNAN 271 -#define SQRT 272 -#define ABS 273 -#define EXP 274 -#define LOG 275 -#define SIN 276 -#define COS 277 -#define TAN 278 -#define ASIN 279 -#define ACOS 280 -#define ATAN 281 -#define CLAMP 282 -#define SEGMENT 283 -#define LT 284 -#define LE 285 -#define GT 286 -#define GE 287 -#define EQ 288 -#define NE 289 -#define NOT 290 -#define AND 291 -#define OR 292 -#define IF 293 -#define ELSE 294 -#define FOR 295 +#define IMAX 271 +#define IMIN 272 +#define ISNAN 273 +#define SQRT 274 +#define ABS 275 +#define EXP 276 +#define LOG 277 +#define SIN 278 +#define COS 279 +#define TAN 280 +#define ASIN 281 +#define ACOS 282 +#define ATAN 283 +#define CLAMP 284 +#define SEGMENT 285 +#define LT 286 +#define LE 287 +#define GT 288 +#define GE 289 +#define EQ 290 +#define NE 291 +#define NOT 292 +#define AND 293 +#define OR 294 +#define IF 295 +#define ELSE 296 +#define FOR 297 @@ -209,7 +213,7 @@ /* Line 214 of yacc.c */ -#line 213 "progs/minccalc/gram.c" +#line 217 "progs/minccalc/gram.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ @@ -221,7 +225,7 @@ /* Line 264 of yacc.c */ -#line 225 "progs/minccalc/gram.c" +#line 229 "progs/minccalc/gram.c" #ifdef short # undef short @@ -434,22 +438,22 @@ #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 65 +#define YYFINAL 69 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 820 +#define YYLAST 800 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 59 +#define YYNTOKENS 61 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 6 /* YYNRULES -- Number of rules. */ -#define YYNRULES 61 +#define YYNRULES 63 /* YYNRULES -- Number of states. */ -#define YYNSTATES 148 +#define YYNSTATES 152 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 295 +#define YYMAXUTOK 297 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -461,15 +465,15 @@ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 45, 46, 43, 41, 54, 42, 49, 44, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 57, 56, - 2, 50, 2, 58, 2, 2, 2, 2, 2, 2, + 47, 48, 45, 43, 56, 44, 51, 46, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 59, 58, + 2, 52, 2, 60, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 47, 2, 48, 51, 2, 2, 2, 2, 2, + 2, 49, 2, 50, 53, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 52, 55, 53, 2, 2, 2, 2, + 2, 2, 2, 54, 57, 55, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -486,7 +490,7 @@ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40 + 35, 36, 37, 38, 39, 40, 41, 42 }; #if YYDEBUG @@ -499,38 +503,39 @@ 81, 85, 89, 93, 97, 101, 105, 109, 113, 118, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 161, 164, 167, 170, 173, 176, 179, - 188, 197, 203, 211, 217, 225, 227, 229, 231, 237, - 243, 245 + 182, 185, 194, 203, 209, 217, 223, 231, 233, 235, + 237, 243, 249, 251 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 60, 0, -1, 61, -1, 62, 56, 61, -1, 62, - 56, -1, 62, -1, 45, 62, 46, -1, 52, 61, - 53, -1, 47, 64, 48, -1, 52, 6, 4, 62, - 55, 62, 53, -1, 45, 62, 57, 62, 46, -1, - 45, 62, 57, 62, 48, -1, 47, 62, 57, 62, - 46, -1, 47, 62, 57, 62, 48, -1, 62, 41, - 62, -1, 62, 42, 62, -1, 42, 62, -1, 62, - 43, 62, -1, 62, 44, 62, -1, 62, 51, 62, - -1, 62, 29, 62, -1, 62, 30, 62, -1, 62, - 31, 62, -1, 62, 32, 62, -1, 62, 33, 62, - -1, 62, 34, 62, -1, 62, 36, 62, -1, 62, - 37, 62, -1, 62, 47, 62, 48, -1, 6, 50, - 62, -1, 11, 63, -1, 35, 62, -1, 10, 62, - -1, 9, 62, -1, 8, 62, -1, 13, 62, -1, - 14, 62, -1, 15, 62, -1, 16, 62, -1, 17, - 62, -1, 18, 62, -1, 19, 62, -1, 20, 62, - -1, 21, 62, -1, 22, 62, -1, 23, 62, -1, - 24, 62, -1, 25, 62, -1, 26, 62, -1, 27, - 45, 62, 54, 62, 54, 62, 46, -1, 28, 45, - 62, 54, 62, 54, 62, 46, -1, 62, 58, 62, - 57, 62, -1, 38, 45, 62, 46, 62, 39, 62, - -1, 38, 45, 62, 46, 62, -1, 40, 52, 6, - 4, 62, 53, 62, -1, 6, -1, 7, -1, 3, - -1, 6, 50, 62, 54, 63, -1, 6, 50, 62, - 4, 62, -1, 62, -1, 64, 54, 62, -1 + 62, 0, -1, 63, -1, 64, 58, 63, -1, 64, + 58, -1, 64, -1, 47, 64, 48, -1, 54, 63, + 55, -1, 49, 66, 50, -1, 54, 6, 4, 64, + 57, 64, 55, -1, 47, 64, 59, 64, 48, -1, + 47, 64, 59, 64, 50, -1, 49, 64, 59, 64, + 48, -1, 49, 64, 59, 64, 50, -1, 64, 43, + 64, -1, 64, 44, 64, -1, 44, 64, -1, 64, + 45, 64, -1, 64, 46, 64, -1, 64, 53, 64, + -1, 64, 31, 64, -1, 64, 32, 64, -1, 64, + 33, 64, -1, 64, 34, 64, -1, 64, 35, 64, + -1, 64, 36, 64, -1, 64, 38, 64, -1, 64, + 39, 64, -1, 64, 49, 64, 50, -1, 6, 52, + 64, -1, 11, 65, -1, 37, 64, -1, 10, 64, + -1, 9, 64, -1, 8, 64, -1, 13, 64, -1, + 14, 64, -1, 15, 64, -1, 16, 64, -1, 17, + 64, -1, 18, 64, -1, 19, 64, -1, 20, 64, + -1, 21, 64, -1, 22, 64, -1, 23, 64, -1, + 24, 64, -1, 25, 64, -1, 26, 64, -1, 27, + 64, -1, 28, 64, -1, 29, 47, 64, 56, 64, + 56, 64, 48, -1, 30, 47, 64, 56, 64, 56, + 64, 48, -1, 64, 60, 64, 59, 64, -1, 40, + 47, 64, 48, 64, 41, 64, -1, 40, 47, 64, + 48, 64, -1, 42, 54, 6, 4, 64, 55, 64, + -1, 6, -1, 7, -1, 3, -1, 6, 52, 64, + 56, 65, -1, 6, 52, 64, 4, 64, -1, 64, + -1, 66, 56, 64, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ @@ -539,10 +544,10 @@ 0, 53, 53, 57, 64, 67, 71, 74, 77, 80, 88, 96, 104, 112, 120, 128, 136, 146, 154, 162, 170, 178, 186, 194, 202, 210, 218, 226, 234, 241, - 248, 251, 258, 264, 270, 276, 282, 288, 294, 301, - 308, 315, 322, 329, 336, 343, 350, 357, 364, 371, - 380, 389, 397, 405, 412, 420, 426, 432, 441, 448, - 457, 462 + 248, 251, 258, 264, 270, 276, 282, 288, 294, 300, + 306, 313, 320, 327, 334, 341, 348, 355, 362, 369, + 376, 383, 392, 401, 409, 417, 424, 432, 438, 444, + 453, 460, 469, 474 }; #endif @@ -552,12 +557,13 @@ static const char *const yytname[] = { "$end", "error", "$undefined", "NAN", "IN", "TO", "IDENT", "REAL", - "AVG", "PROD", "SUM", "LET", "NEG", "LEN", "MAX", "MIN", "ISNAN", "SQRT", - "ABS", "EXP", "LOG", "SIN", "COS", "TAN", "ASIN", "ACOS", "ATAN", - "CLAMP", "SEGMENT", "LT", "LE", "GT", "GE", "EQ", "NE", "NOT", "AND", - "OR", "IF", "ELSE", "FOR", "'+'", "'-'", "'*'", "'/'", "'('", "')'", - "'['", "']'", "'.'", "'='", "'^'", "'{'", "'}'", "','", "'|'", "';'", - "':'", "'?'", "$accept", "top", "exprlist", "expr", "letexpr", "vector", 0 + "AVG", "PROD", "SUM", "LET", "NEG", "LEN", "MAX", "MIN", "IMAX", "IMIN", + "ISNAN", "SQRT", "ABS", "EXP", "LOG", "SIN", "COS", "TAN", "ASIN", + "ACOS", "ATAN", "CLAMP", "SEGMENT", "LT", "LE", "GT", "GE", "EQ", "NE", + "NOT", "AND", "OR", "IF", "ELSE", "FOR", "'+'", "'-'", "'*'", "'/'", + "'('", "')'", "'['", "']'", "'.'", "'='", "'^'", "'{'", "'}'", "','", + "'|'", "';'", "':'", "'?'", "$accept", "top", "exprlist", "expr", + "letexpr", "vector", 0 }; #endif @@ -570,21 +576,22 @@ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 43, 45, 42, 47, 40, 41, 91, 93, 46, - 61, 94, 123, 125, 44, 124, 59, 58, 63 + 295, 296, 297, 43, 45, 42, 47, 40, 41, 91, + 93, 46, 61, 94, 123, 125, 44, 124, 59, 58, + 63 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 59, 60, 61, 61, 61, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, - 64, 64 + 0, 61, 62, 63, 63, 63, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 65, 65, 66, 66 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -594,9 +601,9 @@ 5, 5, 5, 5, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, - 8, 5, 7, 5, 7, 1, 1, 1, 5, 5, - 1, 3 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 8, 8, 5, 7, 5, 7, 1, 1, 1, + 5, 5, 1, 3 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -604,55 +611,57 @@ means the default is an error. */ static const yytype_uint8 yydefact[] = { - 0, 57, 55, 56, 0, 0, 0, 0, 0, 0, + 0, 59, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 5, 0, 34, 33, 32, 0, 30, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 0, 0, 31, 0, 0, 16, - 0, 60, 0, 55, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 5, 0, 34, 33, 32, + 0, 30, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 0, 0, + 31, 0, 0, 16, 0, 62, 0, 57, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 29, 0, 0, 0, 0, 0, 6, 0, - 0, 8, 0, 0, 7, 20, 21, 22, 23, 24, - 25, 26, 27, 14, 15, 17, 18, 0, 19, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 61, 0, - 28, 0, 0, 0, 0, 0, 53, 0, 10, 11, - 12, 13, 0, 51, 59, 58, 0, 0, 0, 0, - 0, 0, 0, 52, 54, 9, 49, 50 + 0, 0, 0, 0, 4, 0, 29, 0, 0, 0, + 0, 0, 6, 0, 0, 8, 0, 0, 7, 20, + 21, 22, 23, 24, 25, 26, 27, 14, 15, 17, + 18, 0, 19, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 63, 0, 28, 0, 0, 0, 0, 0, + 55, 0, 10, 11, 12, 13, 0, 53, 61, 60, + 0, 0, 0, 0, 0, 0, 0, 54, 56, 9, + 51, 52 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 31, 32, 33, 39, 62 + -1, 33, 34, 35, 41, 66 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -76 +#define YYPACT_NINF -48 static const yytype_int16 yypact[] = { - 161, -76, -21, -76, 161, 161, 161, 30, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, -7, -5, 161, -3, -9, 161, 161, 161, - 208, 44, -76, 308, 161, 0, 0, 0, 2, -76, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 161, 161, -12, 161, 39, -12, - 232, 338, -27, -1, 1, -76, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 723, 161, 368, 398, 428, 42, -76, 161, - 161, -76, 161, 161, -76, -10, -10, -10, -10, 769, - 769, 72, 746, -25, -25, -12, -12, 451, -12, -76, - 474, 108, 161, 161, 161, 161, 262, 285, 723, 504, - -76, 161, 161, 30, 534, 564, 594, 617, -76, -76, - -76, -76, 161, 723, 723, -76, 161, 161, 161, 161, - 647, 677, 700, 723, 723, -76, -76, -76 + 167, -48, -21, -48, 167, 167, 167, 27, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 6, 11, 167, 12, -11, 167, + 167, 167, 216, 45, -48, 3, 167, 1, 1, 1, + 8, -48, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 167, 167, + -9, 167, 56, -9, 240, 316, -27, -1, 9, -48, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 701, 167, 346, 376, + 406, 61, -48, 167, 167, -48, 167, 167, -48, 42, + 42, 42, 42, 747, 747, 74, 724, -25, -25, -9, + -9, 429, -9, -48, 452, 112, 167, 167, 167, 167, + 270, 293, 701, 482, -48, 167, 167, 27, 512, 542, + 572, 595, -48, -48, -48, -48, 167, 701, 701, -48, + 167, 167, 167, 167, 625, 655, 678, 701, 701, -48, + -48, -48 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -76, -76, -2, -4, -75, -76 + -48, -48, -2, -4, -47, -48 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -662,176 +671,172 @@ #define YYTABLE_NINF -1 static const yytype_uint8 yytable[] = { - 35, 36, 37, 93, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 76, 77, - 56, 91, 78, 59, 60, 61, 79, 92, 64, 34, - 82, 74, 75, 76, 77, 78, 38, 78, 54, 79, - 55, 79, 57, 58, 65, 87, 115, 78, 135, 34, - 84, 85, 83, 86, 94, 0, 0, 0, 0, 0, - 0, 0, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 0, 110, 109, 111, - 0, 0, 0, 0, 0, 116, 117, 0, 118, 119, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 66, 67, 68, 69, 70, 71, 0, 124, 125, - 126, 127, 122, 74, 75, 76, 77, 133, 134, 78, - 0, 0, 0, 79, 0, 0, 0, 0, 140, 0, - 0, 0, 141, 142, 143, 144, 0, 66, 67, 68, - 69, 70, 71, 0, 72, 73, 0, 0, 0, 74, - 75, 76, 77, 0, 0, 78, 0, 0, 0, 79, - 0, 0, 123, 0, 1, 0, 81, 2, 3, 4, - 5, 6, 7, 0, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 0, 0, 0, 0, 0, 0, 24, 0, 0, 25, - 0, 26, 0, 27, 0, 0, 28, 0, 29, 0, - 0, 1, 0, 30, 63, 3, 4, 5, 6, 7, - 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 0, 0, 0, - 0, 0, 0, 24, 0, 0, 25, 0, 26, 0, - 27, 0, 0, 28, 0, 29, 0, 0, 0, 0, - 30, 66, 67, 68, 69, 70, 71, 0, 72, 73, - 0, 0, 0, 74, 75, 76, 77, 0, 88, 78, - 0, 0, 0, 79, 0, 0, 0, 0, 0, 89, - 81, 66, 67, 68, 69, 70, 71, 0, 72, 73, - 0, 0, 0, 74, 75, 76, 77, 0, 128, 78, - 129, 0, 0, 79, 66, 67, 68, 69, 70, 71, - 81, 72, 73, 0, 0, 0, 74, 75, 76, 77, - 0, 130, 78, 131, 0, 0, 79, 66, 67, 68, - 69, 70, 71, 81, 72, 73, 0, 0, 0, 74, - 75, 76, 77, 0, 0, 78, 0, 0, 0, 79, - 0, 0, 0, 0, 80, 0, 81, 66, 67, 68, - 69, 70, 71, 0, 72, 73, 0, 0, 0, 74, - 75, 76, 77, 0, 0, 78, 0, 0, 0, 79, - 0, 0, 0, 0, 0, 90, 81, 66, 67, 68, - 69, 70, 71, 0, 72, 73, 0, 0, 0, 74, - 75, 76, 77, 0, 0, 78, 0, 0, 0, 79, - 0, 0, 112, 0, 0, 0, 81, 66, 67, 68, - 69, 70, 71, 0, 72, 73, 0, 0, 0, 74, - 75, 76, 77, 0, 0, 78, 0, 0, 0, 79, - 0, 0, 113, 0, 0, 0, 81, 66, 67, 68, - 69, 70, 71, 0, 72, 73, 0, 0, 0, 74, - 75, 76, 77, 0, 114, 78, 0, 0, 0, 79, - 66, 67, 68, 69, 70, 71, 81, 72, 73, 0, - 0, 0, 74, 75, 76, 77, 0, 0, 78, 120, - 0, 0, 79, 66, 67, 68, 69, 70, 71, 81, - 72, 73, 0, 0, 0, 74, 75, 76, 77, 0, - 0, 78, 0, 0, 0, 79, 0, 0, 0, 0, - 0, 121, 81, 66, 67, 68, 69, 70, 71, 0, - 72, 73, 0, 0, 0, 74, 75, 76, 77, 0, - 0, 78, 0, 0, 0, 79, 0, 0, 0, 132, - 0, 0, 81, 66, 67, 68, 69, 70, 71, 0, - 72, 73, 0, 0, 0, 74, 75, 76, 77, 0, - 0, 78, 0, 0, 0, 79, 0, 0, 136, 0, - 0, 0, 81, 66, 67, 68, 69, 70, 71, 0, - 72, 73, 0, 0, 0, 74, 75, 76, 77, 0, - 0, 78, 0, 0, 0, 79, 0, 0, 137, 0, - 0, 0, 81, 66, 67, 68, 69, 70, 71, 0, - 72, 73, 0, 138, 0, 74, 75, 76, 77, 0, - 0, 78, 0, 0, 0, 79, 66, 67, 68, 69, - 70, 71, 81, 72, 73, 0, 0, 0, 74, 75, - 76, 77, 0, 0, 78, 0, 0, 0, 79, 0, - 139, 0, 0, 0, 0, 81, 66, 67, 68, 69, - 70, 71, 0, 72, 73, 0, 0, 0, 74, 75, - 76, 77, 0, 0, 78, 0, 0, 0, 79, 0, - 145, 0, 0, 0, 0, 81, 66, 67, 68, 69, - 70, 71, 0, 72, 73, 0, 0, 0, 74, 75, - 76, 77, 0, 146, 78, 0, 0, 0, 79, 66, - 67, 68, 69, 70, 71, 81, 72, 73, 0, 0, - 0, 74, 75, 76, 77, 0, 147, 78, 0, 0, - 0, 79, 66, 67, 68, 69, 70, 71, 81, 72, - 73, 0, 0, 0, 74, 75, 76, 77, 0, 0, - 78, 0, 0, 0, 79, 66, 67, 68, 69, 70, - 71, 81, 72, 0, 0, 0, 0, 74, 75, 76, - 77, 0, 0, 78, 0, 0, 0, 79, 66, 67, - 68, 69, 0, 0, 0, 0, 0, 0, 0, 0, - 74, 75, 76, 77, 0, 0, 78, 0, 0, 0, - 79 + 37, 38, 39, 97, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 80, 81, 60, 95, 82, 63, 64, 65, 83, 96, + 68, 36, 86, 40, 70, 71, 72, 73, 74, 75, + 82, 76, 77, 62, 83, 69, 78, 79, 80, 81, + 82, 36, 82, 58, 88, 89, 83, 90, 59, 61, + 87, 84, 91, 85, 98, 119, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 139, 114, 113, 115, 0, 78, 79, 80, 81, 120, + 121, 82, 122, 123, 0, 83, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 70, 71, 72, 73, 74, + 75, 0, 128, 129, 130, 131, 126, 78, 79, 80, + 81, 137, 138, 82, 0, 0, 0, 83, 0, 0, + 0, 0, 144, 0, 0, 0, 145, 146, 147, 148, + 0, 0, 0, 70, 71, 72, 73, 74, 75, 0, + 76, 77, 0, 0, 0, 78, 79, 80, 81, 0, + 0, 82, 0, 0, 0, 83, 0, 0, 127, 0, + 1, 0, 85, 2, 3, 4, 5, 6, 7, 0, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, + 0, 0, 0, 0, 26, 0, 0, 27, 0, 28, + 0, 29, 0, 0, 30, 0, 31, 0, 0, 1, + 0, 32, 67, 3, 4, 5, 6, 7, 0, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, + 0, 0, 0, 26, 0, 0, 27, 0, 28, 0, + 29, 0, 0, 30, 0, 31, 0, 0, 0, 0, + 32, 70, 71, 72, 73, 74, 75, 0, 76, 77, + 0, 0, 0, 78, 79, 80, 81, 0, 92, 82, + 0, 0, 0, 83, 0, 0, 0, 0, 0, 93, + 85, 70, 71, 72, 73, 74, 75, 0, 76, 77, + 0, 0, 0, 78, 79, 80, 81, 0, 132, 82, + 133, 0, 0, 83, 70, 71, 72, 73, 74, 75, + 85, 76, 77, 0, 0, 0, 78, 79, 80, 81, + 0, 134, 82, 135, 0, 0, 83, 70, 71, 72, + 73, 74, 75, 85, 76, 77, 0, 0, 0, 78, + 79, 80, 81, 0, 0, 82, 0, 0, 0, 83, + 0, 0, 0, 0, 0, 94, 85, 70, 71, 72, + 73, 74, 75, 0, 76, 77, 0, 0, 0, 78, + 79, 80, 81, 0, 0, 82, 0, 0, 0, 83, + 0, 0, 116, 0, 0, 0, 85, 70, 71, 72, + 73, 74, 75, 0, 76, 77, 0, 0, 0, 78, + 79, 80, 81, 0, 0, 82, 0, 0, 0, 83, + 0, 0, 117, 0, 0, 0, 85, 70, 71, 72, + 73, 74, 75, 0, 76, 77, 0, 0, 0, 78, + 79, 80, 81, 0, 118, 82, 0, 0, 0, 83, + 70, 71, 72, 73, 74, 75, 85, 76, 77, 0, + 0, 0, 78, 79, 80, 81, 0, 0, 82, 124, + 0, 0, 83, 70, 71, 72, 73, 74, 75, 85, + 76, 77, 0, 0, 0, 78, 79, 80, 81, 0, + 0, 82, 0, 0, 0, 83, 0, 0, 0, 0, + 0, 125, 85, 70, 71, 72, 73, 74, 75, 0, + 76, 77, 0, 0, 0, 78, 79, 80, 81, 0, + 0, 82, 0, 0, 0, 83, 0, 0, 0, 136, + 0, 0, 85, 70, 71, 72, 73, 74, 75, 0, + 76, 77, 0, 0, 0, 78, 79, 80, 81, 0, + 0, 82, 0, 0, 0, 83, 0, 0, 140, 0, + 0, 0, 85, 70, 71, 72, 73, 74, 75, 0, + 76, 77, 0, 0, 0, 78, 79, 80, 81, 0, + 0, 82, 0, 0, 0, 83, 0, 0, 141, 0, + 0, 0, 85, 70, 71, 72, 73, 74, 75, 0, + 76, 77, 0, 142, 0, 78, 79, 80, 81, 0, + 0, 82, 0, 0, 0, 83, 70, 71, 72, 73, + 74, 75, 85, 76, 77, 0, 0, 0, 78, 79, + 80, 81, 0, 0, 82, 0, 0, 0, 83, 0, + 143, 0, 0, 0, 0, 85, 70, 71, 72, 73, + 74, 75, 0, 76, 77, 0, 0, 0, 78, 79, + 80, 81, 0, 0, 82, 0, 0, 0, 83, 0, + 149, 0, 0, 0, 0, 85, 70, 71, 72, 73, + 74, 75, 0, 76, 77, 0, 0, 0, 78, 79, + 80, 81, 0, 150, 82, 0, 0, 0, 83, 70, + 71, 72, 73, 74, 75, 85, 76, 77, 0, 0, + 0, 78, 79, 80, 81, 0, 151, 82, 0, 0, + 0, 83, 70, 71, 72, 73, 74, 75, 85, 76, + 77, 0, 0, 0, 78, 79, 80, 81, 0, 0, + 82, 0, 0, 0, 83, 70, 71, 72, 73, 74, + 75, 85, 76, 0, 0, 0, 0, 78, 79, 80, + 81, 0, 0, 82, 0, 0, 0, 83, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 0, 0, 0, + 78, 79, 80, 81, 0, 0, 82, 0, 0, 0, + 83 }; static const yytype_int16 yycheck[] = { 4, 5, 6, 4, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 43, 44, - 24, 48, 47, 27, 28, 29, 51, 54, 30, 50, - 34, 41, 42, 43, 44, 47, 6, 47, 45, 51, - 45, 51, 45, 52, 0, 6, 4, 47, 123, 50, - 54, 55, 50, 57, 53, -1, -1, -1, -1, -1, - -1, -1, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, -1, 81, 80, 83, - -1, -1, -1, -1, -1, 89, 90, -1, 92, 93, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 29, 30, 31, 32, 33, 34, -1, 112, 113, - 114, 115, 4, 41, 42, 43, 44, 121, 122, 47, - -1, -1, -1, 51, -1, -1, -1, -1, 132, -1, - -1, -1, 136, 137, 138, 139, -1, 29, 30, 31, - 32, 33, 34, -1, 36, 37, -1, -1, -1, 41, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, -1, 54, -1, 3, -1, 58, 6, 7, 8, - 9, 10, 11, -1, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - -1, -1, -1, -1, -1, -1, 35, -1, -1, 38, - -1, 40, -1, 42, -1, -1, 45, -1, 47, -1, - -1, 3, -1, 52, 6, 7, 8, 9, 10, 11, - -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, -1, -1, -1, - -1, -1, -1, 35, -1, -1, 38, -1, 40, -1, - 42, -1, -1, 45, -1, 47, -1, -1, -1, -1, - 52, 29, 30, 31, 32, 33, 34, -1, 36, 37, - -1, -1, -1, 41, 42, 43, 44, -1, 46, 47, - -1, -1, -1, 51, -1, -1, -1, -1, -1, 57, - 58, 29, 30, 31, 32, 33, 34, -1, 36, 37, - -1, -1, -1, 41, 42, 43, 44, -1, 46, 47, - 48, -1, -1, 51, 29, 30, 31, 32, 33, 34, - 58, 36, 37, -1, -1, -1, 41, 42, 43, 44, - -1, 46, 47, 48, -1, -1, 51, 29, 30, 31, - 32, 33, 34, 58, 36, 37, -1, -1, -1, 41, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, -1, -1, -1, 56, -1, 58, 29, 30, 31, - 32, 33, 34, -1, 36, 37, -1, -1, -1, 41, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, -1, -1, -1, -1, 57, 58, 29, 30, 31, - 32, 33, 34, -1, 36, 37, -1, -1, -1, 41, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, -1, 54, -1, -1, -1, 58, 29, 30, 31, - 32, 33, 34, -1, 36, 37, -1, -1, -1, 41, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, -1, 54, -1, -1, -1, 58, 29, 30, 31, - 32, 33, 34, -1, 36, 37, -1, -1, -1, 41, - 42, 43, 44, -1, 46, 47, -1, -1, -1, 51, - 29, 30, 31, 32, 33, 34, 58, 36, 37, -1, - -1, -1, 41, 42, 43, 44, -1, -1, 47, 48, - -1, -1, 51, 29, 30, 31, 32, 33, 34, 58, - 36, 37, -1, -1, -1, 41, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, -1, -1, -1, - -1, 57, 58, 29, 30, 31, 32, 33, 34, -1, - 36, 37, -1, -1, -1, 41, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, -1, -1, 55, - -1, -1, 58, 29, 30, 31, 32, 33, 34, -1, - 36, 37, -1, -1, -1, 41, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, -1, 54, -1, - -1, -1, 58, 29, 30, 31, 32, 33, 34, -1, - 36, 37, -1, -1, -1, 41, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, -1, 54, -1, - -1, -1, 58, 29, 30, 31, 32, 33, 34, -1, - 36, 37, -1, 39, -1, 41, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, 29, 30, 31, 32, - 33, 34, 58, 36, 37, -1, -1, -1, 41, 42, - 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, - 53, -1, -1, -1, -1, 58, 29, 30, 31, 32, - 33, 34, -1, 36, 37, -1, -1, -1, 41, 42, - 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, - 53, -1, -1, -1, -1, 58, 29, 30, 31, 32, - 33, 34, -1, 36, 37, -1, -1, -1, 41, 42, - 43, 44, -1, 46, 47, -1, -1, -1, 51, 29, - 30, 31, 32, 33, 34, 58, 36, 37, -1, -1, - -1, 41, 42, 43, 44, -1, 46, 47, -1, -1, - -1, 51, 29, 30, 31, 32, 33, 34, 58, 36, - 37, -1, -1, -1, 41, 42, 43, 44, -1, -1, - 47, -1, -1, -1, 51, 29, 30, 31, 32, 33, - 34, 58, 36, -1, -1, -1, -1, 41, 42, 43, - 44, -1, -1, 47, -1, -1, -1, 51, 29, 30, - 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, - 41, 42, 43, 44, -1, -1, 47, -1, -1, -1, - 51 + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 45, 46, 26, 50, 49, 29, 30, 31, 53, 56, + 32, 52, 36, 6, 31, 32, 33, 34, 35, 36, + 49, 38, 39, 54, 53, 0, 43, 44, 45, 46, + 49, 52, 49, 47, 58, 59, 53, 61, 47, 47, + 52, 58, 6, 60, 55, 4, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 127, 85, 84, 87, -1, 43, 44, 45, 46, 93, + 94, 49, 96, 97, -1, 53, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 31, 32, 33, 34, 35, + 36, -1, 116, 117, 118, 119, 4, 43, 44, 45, + 46, 125, 126, 49, -1, -1, -1, 53, -1, -1, + -1, -1, 136, -1, -1, -1, 140, 141, 142, 143, + -1, -1, -1, 31, 32, 33, 34, 35, 36, -1, + 38, 39, -1, -1, -1, 43, 44, 45, 46, -1, + -1, 49, -1, -1, -1, 53, -1, -1, 56, -1, + 3, -1, 60, 6, 7, 8, 9, 10, 11, -1, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, -1, -1, + -1, -1, -1, -1, 37, -1, -1, 40, -1, 42, + -1, 44, -1, -1, 47, -1, 49, -1, -1, 3, + -1, 54, 6, 7, 8, 9, 10, 11, -1, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, -1, -1, -1, + -1, -1, -1, 37, -1, -1, 40, -1, 42, -1, + 44, -1, -1, 47, -1, 49, -1, -1, -1, -1, + 54, 31, 32, 33, 34, 35, 36, -1, 38, 39, + -1, -1, -1, 43, 44, 45, 46, -1, 48, 49, + -1, -1, -1, 53, -1, -1, -1, -1, -1, 59, + 60, 31, 32, 33, 34, 35, 36, -1, 38, 39, + -1, -1, -1, 43, 44, 45, 46, -1, 48, 49, + 50, -1, -1, 53, 31, 32, 33, 34, 35, 36, + 60, 38, 39, -1, -1, -1, 43, 44, 45, 46, + -1, 48, 49, 50, -1, -1, 53, 31, 32, 33, + 34, 35, 36, 60, 38, 39, -1, -1, -1, 43, + 44, 45, 46, -1, -1, 49, -1, -1, -1, 53, + -1, -1, -1, -1, -1, 59, 60, 31, 32, 33, + 34, 35, 36, -1, 38, 39, -1, -1, -1, 43, + 44, 45, 46, -1, -1, 49, -1, -1, -1, 53, + -1, -1, 56, -1, -1, -1, 60, 31, 32, 33, + 34, 35, 36, -1, 38, 39, -1, -1, -1, 43, + 44, 45, 46, -1, -1, 49, -1, -1, -1, 53, + -1, -1, 56, -1, -1, -1, 60, 31, 32, 33, + 34, 35, 36, -1, 38, 39, -1, -1, -1, 43, + 44, 45, 46, -1, 48, 49, -1, -1, -1, 53, + 31, 32, 33, 34, 35, 36, 60, 38, 39, -1, + -1, -1, 43, 44, 45, 46, -1, -1, 49, 50, + -1, -1, 53, 31, 32, 33, 34, 35, 36, 60, + 38, 39, -1, -1, -1, 43, 44, 45, 46, -1, + -1, 49, -1, -1, -1, 53, -1, -1, -1, -1, + -1, 59, 60, 31, 32, 33, 34, 35, 36, -1, + 38, 39, -1, -1, -1, 43, 44, 45, 46, -1, + -1, 49, -1, -1, -1, 53, -1, -1, -1, 57, + -1, -1, 60, 31, 32, 33, 34, 35, 36, -1, + 38, 39, -1, -1, -1, 43, 44, 45, 46, -1, + -1, 49, -1, -1, -1, 53, -1, -1, 56, -1, + -1, -1, 60, 31, 32, 33, 34, 35, 36, -1, + 38, 39, -1, -1, -1, 43, 44, 45, 46, -1, + -1, 49, -1, -1, -1, 53, -1, -1, 56, -1, + -1, -1, 60, 31, 32, 33, 34, 35, 36, -1, + 38, 39, -1, 41, -1, 43, 44, 45, 46, -1, + -1, 49, -1, -1, -1, 53, 31, 32, 33, 34, + 35, 36, 60, 38, 39, -1, -1, -1, 43, 44, + 45, 46, -1, -1, 49, -1, -1, -1, 53, -1, + 55, -1, -1, -1, -1, 60, 31, 32, 33, 34, + 35, 36, -1, 38, 39, -1, -1, -1, 43, 44, + 45, 46, -1, -1, 49, -1, -1, -1, 53, -1, + 55, -1, -1, -1, -1, 60, 31, 32, 33, 34, + 35, 36, -1, 38, 39, -1, -1, -1, 43, 44, + 45, 46, -1, 48, 49, -1, -1, -1, 53, 31, + 32, 33, 34, 35, 36, 60, 38, 39, -1, -1, + -1, 43, 44, 45, 46, -1, 48, 49, -1, -1, + -1, 53, 31, 32, 33, 34, 35, 36, 60, 38, + 39, -1, -1, -1, 43, 44, 45, 46, -1, -1, + 49, -1, -1, -1, 53, 31, 32, 33, 34, 35, + 36, 60, 38, -1, -1, -1, -1, 43, 44, 45, + 46, -1, -1, 49, -1, -1, -1, 53, 31, 32, + 33, 34, -1, -1, -1, -1, -1, -1, -1, -1, + 43, 44, 45, 46, -1, -1, 49, -1, -1, -1, + 53 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -840,19 +845,20 @@ { 0, 3, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 35, 38, 40, 42, 45, 47, - 52, 60, 61, 62, 50, 62, 62, 62, 6, 63, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 45, 45, 62, 45, 52, 62, - 62, 62, 64, 6, 61, 0, 29, 30, 31, 32, - 33, 34, 36, 37, 41, 42, 43, 44, 47, 51, - 56, 58, 62, 50, 62, 62, 62, 6, 46, 57, - 57, 48, 54, 4, 53, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 61, - 62, 62, 54, 54, 46, 4, 62, 62, 62, 62, - 48, 57, 4, 54, 62, 62, 62, 62, 46, 48, - 46, 48, 55, 62, 62, 63, 54, 54, 39, 53, - 62, 62, 62, 62, 62, 53, 46, 46 + 25, 26, 27, 28, 29, 30, 37, 40, 42, 44, + 47, 49, 54, 62, 63, 64, 52, 64, 64, 64, + 6, 65, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 47, 47, + 64, 47, 54, 64, 64, 64, 66, 6, 63, 0, + 31, 32, 33, 34, 35, 36, 38, 39, 43, 44, + 45, 46, 49, 53, 58, 60, 64, 52, 64, 64, + 64, 6, 48, 59, 59, 50, 56, 4, 55, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 63, 64, 64, 56, 56, 48, 4, + 64, 64, 64, 64, 50, 59, 4, 56, 64, 64, + 64, 64, 48, 50, 48, 50, 57, 64, 64, 65, + 56, 56, 41, 55, 64, 64, 64, 64, 64, 55, + 48, 48 }; #define yyerrok (yyerrstatus = 0) @@ -2052,15 +2058,35 @@ #line 295 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); - (yyval.node)->type = NODETYPE_ISNAN; - (yyval.node)->flags |= ALLARGS_SCALAR; + (yyval.node)->type = NODETYPE_IMAX; (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; case 39: /* Line 1455 of yacc.c */ -#line 302 "gram.y" +#line 301 "gram.y" + { (yyval.node) = new_scalar_node(1); + (yyval.node)->pos = (yyvsp[(1) - (2)].pos); + (yyval.node)->type = NODETYPE_IMIN; + (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } + break; + + case 40: + +/* Line 1455 of yacc.c */ +#line 307 "gram.y" + { (yyval.node) = new_scalar_node(1); + (yyval.node)->pos = (yyvsp[(1) - (2)].pos); + (yyval.node)->type = NODETYPE_ISNAN; + (yyval.node)->flags |= ALLARGS_SCALAR; + (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } + break; + + case 41: + +/* Line 1455 of yacc.c */ +#line 314 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_SQRT; @@ -2068,10 +2094,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 40: + case 42: /* Line 1455 of yacc.c */ -#line 309 "gram.y" +#line 321 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_ABS; @@ -2079,10 +2105,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 41: + case 43: /* Line 1455 of yacc.c */ -#line 316 "gram.y" +#line 328 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_EXP; @@ -2090,10 +2116,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 42: + case 44: /* Line 1455 of yacc.c */ -#line 323 "gram.y" +#line 335 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_LOG; @@ -2101,10 +2127,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 43: + case 45: /* Line 1455 of yacc.c */ -#line 330 "gram.y" +#line 342 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_SIN; @@ -2112,10 +2138,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 44: + case 46: /* Line 1455 of yacc.c */ -#line 337 "gram.y" +#line 349 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_COS; @@ -2123,10 +2149,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 45: + case 47: /* Line 1455 of yacc.c */ -#line 344 "gram.y" +#line 356 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_TAN; @@ -2134,10 +2160,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 46: + case 48: /* Line 1455 of yacc.c */ -#line 351 "gram.y" +#line 363 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_ASIN; @@ -2145,10 +2171,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 47: + case 49: /* Line 1455 of yacc.c */ -#line 358 "gram.y" +#line 370 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_ACOS; @@ -2156,10 +2182,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 48: + case 50: /* Line 1455 of yacc.c */ -#line 365 "gram.y" +#line 377 "gram.y" { (yyval.node) = new_scalar_node(1); (yyval.node)->pos = (yyvsp[(1) - (2)].pos); (yyval.node)->type = NODETYPE_ATAN; @@ -2167,10 +2193,10 @@ (yyval.node)->expr[0] = (yyvsp[(2) - (2)].node); } break; - case 49: + case 51: /* Line 1455 of yacc.c */ -#line 372 "gram.y" +#line 384 "gram.y" { (yyval.node) = new_scalar_node(3); (yyval.node)->pos = (yyvsp[(1) - (8)].pos); (yyval.node)->type = NODETYPE_CLAMP; @@ -2180,10 +2206,10 @@ (yyval.node)->expr[2] = (yyvsp[(7) - (8)].node); } break; - case 50: + case 52: /* Line 1455 of yacc.c */ -#line 381 "gram.y" +#line 393 "gram.y" { (yyval.node) = new_scalar_node(3); (yyval.node)->pos = (yyvsp[(1) - (8)].pos); (yyval.node)->type = NODETYPE_SEGMENT; @@ -2193,10 +2219,10 @@ (yyval.node)->expr[2] = (yyvsp[(7) - (8)].node); } break; - case 51: + case 53: /* Line 1455 of yacc.c */ -#line 390 "gram.y" +#line 402 "gram.y" { (yyval.node) = new_node(3, node_is_scalar((yyvsp[(3) - (5)].node))); (yyval.node)->pos = (yyvsp[(2) - (5)].pos); (yyval.node)->type = NODETYPE_IFELSE; @@ -2205,10 +2231,10 @@ (yyval.node)->expr[2] = (yyvsp[(5) - (5)].node); } break; - case 52: + case 54: /* Line 1455 of yacc.c */ -#line 398 "gram.y" +#line 410 "gram.y" { (yyval.node) = new_node(3, node_is_scalar((yyvsp[(5) - (7)].node))); (yyval.node)->pos = (yyvsp[(1) - (7)].pos); (yyval.node)->type = NODETYPE_IFELSE; @@ -2217,10 +2243,10 @@ (yyval.node)->expr[2] = (yyvsp[(7) - (7)].node); } break; - case 53: + case 55: /* Line 1455 of yacc.c */ -#line 406 "gram.y" +#line 418 "gram.y" { (yyval.node) = new_node(2, node_is_scalar((yyvsp[(5) - (5)].node))); (yyval.node)->pos = (yyvsp[(1) - (5)].pos); (yyval.node)->type = NODETYPE_IFELSE; @@ -2228,10 +2254,10 @@ (yyval.node)->expr[1] = (yyvsp[(5) - (5)].node); } break; - case 54: + case 56: /* Line 1455 of yacc.c */ -#line 413 "gram.y" +#line 425 "gram.y" { (yyval.node) = new_scalar_node(2); (yyval.node)->pos = (yyvsp[(1) - (7)].pos); (yyval.node)->type = NODETYPE_FOR; @@ -2240,40 +2266,40 @@ (yyval.node)->expr[1] = (yyvsp[(7) - (7)].node); } break; - case 55: + case 57: /* Line 1455 of yacc.c */ -#line 421 "gram.y" +#line 433 "gram.y" { (yyval.node) = new_node(0, ident_is_scalar((yyvsp[(1) - (1)].ident))); (yyval.node)->type = NODETYPE_IDENT; (yyval.node)->pos = -1; (yyval.node)->ident = (yyvsp[(1) - (1)].ident); } break; - case 56: + case 58: /* Line 1455 of yacc.c */ -#line 427 "gram.y" +#line 439 "gram.y" { (yyval.node) = new_scalar_node(0); (yyval.node)->pos = -1; (yyval.node)->type = NODETYPE_REAL; (yyval.node)->real = (yyvsp[(1) - (1)].real); } break; - case 57: + case 59: /* Line 1455 of yacc.c */ -#line 433 "gram.y" +#line 445 "gram.y" { (yyval.node) = new_scalar_node(0); (yyval.node)->pos = -1; (yyval.node)->type = NODETYPE_REAL; (yyval.node)->real = INVALID_VALUE; } break; - case 58: + case 60: /* Line 1455 of yacc.c */ -#line 442 "gram.y" +#line 454 "gram.y" { (yyval.node) = new_scalar_node(2); (yyval.node)->type = NODETYPE_LET; (yyval.node)->pos = (yyvsp[(2) - (5)].pos); @@ -2282,10 +2308,10 @@ (yyval.node)->expr[1] = (yyvsp[(5) - (5)].node); } break; - case 59: + case 61: /* Line 1455 of yacc.c */ -#line 449 "gram.y" +#line 461 "gram.y" { (yyval.node) = new_scalar_node(2); (yyval.node)->pos = (yyvsp[(2) - (5)].pos); (yyval.node)->type = NODETYPE_LET; @@ -2294,20 +2320,20 @@ (yyval.node)->expr[1] = (yyvsp[(5) - (5)].node); } break; - case 60: + case 62: /* Line 1455 of yacc.c */ -#line 458 "gram.y" +#line 470 "gram.y" { (yyval.node) = new_vector_node(1); (yyval.node)->pos = (yyvsp[(1) - (1)].node)->pos; (yyval.node)->type = NODETYPE_VEC1; (yyval.node)->expr[0] = (yyvsp[(1) - (1)].node); } break; - case 61: + case 63: /* Line 1455 of yacc.c */ -#line 463 "gram.y" +#line 475 "gram.y" { (yyval.node) = new_vector_node(2); (yyval.node)->pos = (yyvsp[(2) - (3)].pos); (yyval.node)->type = NODETYPE_VEC2; @@ -2318,7 +2344,7 @@ /* Line 1455 of yacc.c */ -#line 2322 "progs/minccalc/gram.c" +#line 2348 "progs/minccalc/gram.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -2530,7 +2556,7 @@ /* Line 1675 of yacc.c */ -#line 470 "gram.y" +#line 482 "gram.y" node_t root;
--- a/progs/minccalc/gram.y +++ b/progs/minccalc/gram.y @@ -20,7 +20,7 @@ } %token NAN -%token IN TO IDENT REAL AVG PROD SUM LET NEG LEN MAX MIN +%token IN TO IDENT REAL AVG PROD SUM LET NEG LEN MAX MIN IMAX IMIN %token ISNAN SQRT ABS EXP LOG SIN COS TAN ASIN ACOS ATAN CLAMP SEGMENT %token LT LE GT GE EQ NE NOT AND OR %token IF ELSE FOR @@ -28,7 +28,7 @@ %type<ident> IDENT %type<real> REAL %type<pos> IN TO AVG SUM PROD LET NEG LEN IF ELSE FOR -%type<pos> ISNAN SQRT ABS MAX MIN EXP LOG SIN COS TAN ASIN ACOS ATAN +%type<pos> ISNAN SQRT ABS MAX MIN IMAX IMIN EXP LOG SIN COS TAN ASIN ACOS ATAN %type<pos> CLAMP SEGMENT %type<pos> NOT LT LE GT GE EQ NE AND OR %type<pos> '+' '-' '*' '/' '(' ')' '[' ']' '.' '=' '^' '{' '}' ',' '|' ';' @@ -46,7 +46,7 @@ %left '*' '/' %right NEG NOT %right '^' -%right AVG SUM PROD LEN ISNAN SQRT ABS MAX MIN EXP LOG SIN COS TAN ASIN ACOS ATAN +%right AVG SUM PROD LEN ISNAN SQRT ABS MAX MIN IMAX IMIN EXP LOG SIN COS TAN ASIN ACOS ATAN %% @@ -291,6 +291,18 @@ $$->type = NODETYPE_MIN; $$->expr[0] = $2; } + | IMAX expr + { $$ = new_scalar_node(1); + $$->pos = $1; + $$->type = NODETYPE_IMAX; + $$->expr[0] = $2; } + + | IMIN expr + { $$ = new_scalar_node(1); + $$->pos = $1; + $$->type = NODETYPE_IMIN; + $$->expr[0] = $2; } + | ISNAN expr { $$ = new_scalar_node(1); $$->pos = $1;
--- a/progs/minccalc/lex.c +++ b/progs/minccalc/lex.c @@ -1,6 +1,5 @@ -#line 2 "minccalc/lex.c" -#line 4 "minccalc/lex.c" +#line 3 "progs/minccalc/lex.c" #define YY_INT_ALIGNED short int @@ -9,7 +8,7 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 33 +#define YY_FLEX_SUBMINOR_VERSION 35 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -31,7 +30,7 @@ /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ -#if __STDC_VERSION__ >= 199901L +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. @@ -54,7 +53,6 @@ typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN @@ -85,6 +83,8 @@ #define UINT32_MAX (4294967295U) #endif +#endif /* ! C99 */ + #endif /* ! FLEXINT_H */ #ifdef __cplusplus @@ -94,11 +94,12 @@ #else /* ! __cplusplus */ -#if __STDC__ +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) #define YY_USE_CONST -#endif /* __STDC__ */ +#endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST @@ -140,7 +141,15 @@ /* Size of default input buffer. */ #ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else #define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. @@ -178,14 +187,9 @@ #define unput(c) yyunput( c, (yytext_ptr) ) -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ - #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T -typedef unsigned int yy_size_t; +typedef size_t yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE @@ -364,8 +368,8 @@ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 40 -#define YY_END_OF_BUFFER 41 +#define YY_NUM_RULES 42 +#define YY_END_OF_BUFFER 43 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -373,20 +377,20 @@ flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[103] = +static yyconst flex_int16_t yy_accept[108] = { 0, - 0, 0, 41, 39, 38, 38, 33, 39, 37, 27, - 39, 29, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 39, 38, 32, 34, 37, 37, - 0, 28, 31, 30, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 23, 21, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 22, - 35, 37, 0, 37, 26, 8, 36, 36, 36, 1, - 36, 14, 36, 11, 25, 36, 5, 4, 12, 9, - 10, 36, 36, 13, 36, 2, 15, 17, 16, 18, - 36, 24, 36, 3, 36, 7, 19, 6, 36, 36, + 0, 0, 43, 41, 40, 40, 35, 41, 39, 29, + 41, 31, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 41, 40, 34, 36, 39, 39, + 0, 30, 33, 32, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 25, 38, 23, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 24, 37, 39, 0, 39, 28, 8, 38, 38, 38, + 1, 38, 16, 38, 13, 27, 38, 38, 38, 5, + 4, 14, 9, 10, 38, 38, 15, 38, 2, 17, + 19, 18, 20, 38, 26, 11, 12, 38, 3, 38, - 20, 0 + 7, 21, 6, 38, 38, 22, 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -429,80 +433,82 @@ 2, 2, 2, 2, 2, 1 } ; -static yyconst flex_int16_t yy_base[104] = +static yyconst flex_int16_t yy_base[109] = { 0, - 0, 0, 130, 131, 35, 37, 119, 123, 34, 117, - 116, 115, 0, 108, 26, 21, 26, 96, 25, 32, - 39, 92, 43, 37, 85, 65, 131, 131, 57, 66, - 63, 131, 131, 131, 0, 106, 88, 91, 94, 100, - 93, 98, 82, 81, 83, 80, 0, 0, 83, 49, - 86, 72, 80, 78, 82, 77, 72, 76, 74, 0, - 131, 70, 91, 90, 0, 0, 66, 70, 69, 0, - 69, 0, 73, 0, 0, 76, 0, 0, 0, 0, - 0, 72, 64, 0, 56, 0, 0, 0, 0, 0, - 59, 0, 59, 0, 64, 0, 0, 0, 56, 48, + 0, 0, 135, 136, 35, 37, 124, 128, 34, 122, + 121, 120, 0, 113, 26, 21, 26, 101, 38, 26, + 33, 97, 42, 39, 90, 49, 136, 136, 59, 69, + 62, 136, 136, 136, 0, 111, 93, 96, 99, 105, + 98, 103, 87, 86, 88, 85, 0, 57, 0, 88, + 52, 91, 77, 85, 83, 87, 82, 77, 81, 79, + 0, 136, 73, 96, 95, 0, 0, 71, 75, 74, + 0, 74, 0, 78, 0, 0, 62, 70, 79, 0, + 0, 0, 0, 0, 75, 67, 0, 59, 0, 0, + 0, 0, 0, 62, 0, 0, 0, 62, 0, 67, - 0, 131, 47 + 0, 0, 0, 59, 51, 0, 136, 72 } ; -static yyconst flex_int16_t yy_def[104] = +static yyconst flex_int16_t yy_def[109] = { 0, - 102, 1, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 107, 1, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 107, 107, 107, 107, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 103, 0, 102 + 108, 108, 108, 108, 108, 108, 0, 107 } ; -static yyconst flex_int16_t yy_nxt[168] = +static yyconst flex_int16_t yy_nxt[173] = { 0, 4, 5, 6, 7, 8, 4, 4, 9, 10, 11, 12, 13, 13, 14, 4, 15, 13, 16, 13, 17, 18, 13, 19, 20, 21, 13, 13, 22, 13, 13, 23, 24, 13, 13, 13, 25, 26, 26, 26, 26, - 29, 30, 37, 38, 42, 47, 31, 43, 35, 44, - 48, 50, 59, 31, 52, 49, 39, 40, 51, 41, - 45, 53, 55, 60, 62, 56, 26, 26, 63, 31, - 64, 57, 29, 30, 77, 58, 31, 62, 31, 101, - 78, 100, 31, 99, 98, 31, 97, 96, 95, 31, - 94, 93, 92, 91, 90, 89, 88, 64, 64, 87, + 29, 30, 37, 38, 42, 51, 31, 43, 53, 44, + 26, 26, 52, 31, 60, 54, 39, 40, 47, 41, + 45, 56, 48, 49, 57, 61, 63, 64, 50, 65, + 58, 31, 77, 35, 59, 29, 30, 80, 31, 78, + 63, 31, 106, 81, 105, 31, 104, 103, 31, 102, + 101, 100, 31, 99, 98, 97, 96, 95, 94, 93, - 86, 85, 84, 83, 82, 81, 80, 79, 76, 75, - 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, - 61, 54, 46, 36, 34, 33, 32, 28, 27, 102, - 3, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102 + 92, 91, 65, 65, 90, 89, 88, 87, 86, 85, + 84, 83, 82, 79, 76, 75, 74, 73, 72, 71, + 70, 69, 68, 67, 66, 62, 55, 46, 36, 34, + 33, 32, 28, 27, 107, 3, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107 } ; -static yyconst flex_int16_t yy_chk[168] = +static yyconst flex_int16_t yy_chk[173] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 6, 6, - 9, 9, 15, 15, 16, 19, 9, 16, 103, 17, - 19, 20, 24, 9, 21, 19, 15, 15, 20, 15, - 17, 21, 23, 24, 29, 23, 26, 26, 31, 29, - 31, 23, 30, 30, 50, 23, 29, 62, 30, 100, - 50, 99, 62, 95, 93, 30, 91, 85, 83, 62, - 82, 76, 73, 71, 69, 68, 67, 64, 63, 59, + 9, 9, 15, 15, 16, 20, 9, 16, 21, 17, + 26, 26, 20, 9, 24, 21, 15, 15, 19, 15, + 17, 23, 19, 19, 23, 24, 29, 31, 19, 31, + 23, 29, 48, 108, 23, 30, 30, 51, 29, 48, + 63, 30, 105, 51, 104, 63, 100, 98, 30, 94, + 88, 86, 63, 85, 79, 78, 77, 74, 72, 70, - 58, 57, 56, 55, 54, 53, 52, 51, 49, 46, - 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, - 25, 22, 18, 14, 12, 11, 10, 8, 7, 3, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102 + 69, 68, 65, 64, 60, 59, 58, 57, 56, 55, + 54, 53, 52, 50, 46, 45, 44, 43, 42, 41, + 40, 39, 38, 37, 36, 25, 22, 18, 14, 12, + 11, 10, 8, 7, 3, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107 } ; static yy_state_type yy_last_accepting_state; @@ -519,15 +525,15 @@ #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; -#line 1 "minccalc/lex.l" -#line 2 "minccalc/lex.l" +#line 1 "lex.l" +#line 2 "lex.l" #include <string.h> #include "node.h" -#include "y.tab.h" +#include "gram.h" int lexpos = 0; #define setpos() yylval.pos = lexpos; lexpos += yyleng -#line 531 "minccalc/lex.c" +#line 537 "progs/minccalc/lex.c" #define INITIAL 0 @@ -545,6 +551,35 @@ static int yy_init_globals (void ); +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * out_str ); + +int yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int line_number ); + /* Macros after this point can all be overridden by user definitions in * section 1. */ @@ -579,7 +614,12 @@ /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else #define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ @@ -587,7 +627,7 @@ /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -680,10 +720,10 @@ register char *yy_cp, *yy_bp; register int yy_act; -#line 10 "minccalc/lex.l" +#line 10 "lex.l" -#line 687 "minccalc/lex.c" +#line 727 "progs/minccalc/lex.c" if ( !(yy_init) ) { @@ -736,13 +776,13 @@ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 103 ) + if ( yy_current_state >= 108 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 131 ); + while ( yy_base[yy_current_state] != 136 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -768,214 +808,224 @@ case 1: YY_RULE_SETUP -#line 12 "minccalc/lex.l" +#line 12 "lex.l" setpos(); return AVG; YY_BREAK case 2: YY_RULE_SETUP -#line 13 "minccalc/lex.l" +#line 13 "lex.l" setpos(); return SUM; YY_BREAK case 3: YY_RULE_SETUP -#line 14 "minccalc/lex.l" +#line 14 "lex.l" setpos(); return PROD; YY_BREAK case 4: YY_RULE_SETUP -#line 15 "minccalc/lex.l" +#line 15 "lex.l" setpos(); return LET; YY_BREAK case 5: YY_RULE_SETUP -#line 16 "minccalc/lex.l" +#line 16 "lex.l" setpos(); return LEN; YY_BREAK case 6: YY_RULE_SETUP -#line 17 "minccalc/lex.l" +#line 17 "lex.l" setpos(); return ISNAN; YY_BREAK case 7: YY_RULE_SETUP -#line 18 "minccalc/lex.l" +#line 18 "lex.l" setpos(); return SQRT; YY_BREAK case 8: YY_RULE_SETUP -#line 19 "minccalc/lex.l" +#line 19 "lex.l" setpos(); return ABS; YY_BREAK case 9: YY_RULE_SETUP -#line 20 "minccalc/lex.l" +#line 20 "lex.l" setpos(); return MAX; YY_BREAK case 10: YY_RULE_SETUP -#line 21 "minccalc/lex.l" +#line 21 "lex.l" setpos(); return MIN; YY_BREAK case 11: YY_RULE_SETUP -#line 22 "minccalc/lex.l" -setpos(); return EXP; +#line 22 "lex.l" +setpos(); return IMAX; YY_BREAK case 12: YY_RULE_SETUP -#line 23 "minccalc/lex.l" -setpos(); return LOG; +#line 23 "lex.l" +setpos(); return IMIN; YY_BREAK case 13: YY_RULE_SETUP -#line 24 "minccalc/lex.l" -setpos(); return SIN; +#line 24 "lex.l" +setpos(); return EXP; YY_BREAK case 14: YY_RULE_SETUP -#line 25 "minccalc/lex.l" -setpos(); return COS; +#line 25 "lex.l" +setpos(); return LOG; YY_BREAK case 15: YY_RULE_SETUP -#line 26 "minccalc/lex.l" -setpos(); return TAN; +#line 26 "lex.l" +setpos(); return SIN; YY_BREAK case 16: YY_RULE_SETUP -#line 27 "minccalc/lex.l" -setpos(); return ASIN; +#line 27 "lex.l" +setpos(); return COS; YY_BREAK case 17: YY_RULE_SETUP -#line 28 "minccalc/lex.l" -setpos(); return ACOS; +#line 28 "lex.l" +setpos(); return TAN; YY_BREAK case 18: YY_RULE_SETUP -#line 29 "minccalc/lex.l" -setpos(); return ATAN; +#line 29 "lex.l" +setpos(); return ASIN; YY_BREAK case 19: YY_RULE_SETUP -#line 30 "minccalc/lex.l" -setpos(); return CLAMP; +#line 30 "lex.l" +setpos(); return ACOS; YY_BREAK case 20: YY_RULE_SETUP -#line 31 "minccalc/lex.l" -setpos(); return SEGMENT; +#line 31 "lex.l" +setpos(); return ATAN; YY_BREAK case 21: YY_RULE_SETUP -#line 32 "minccalc/lex.l" -setpos(); return IN; +#line 32 "lex.l" +setpos(); return CLAMP; YY_BREAK case 22: YY_RULE_SETUP -#line 33 "minccalc/lex.l" -setpos(); return TO; +#line 33 "lex.l" +setpos(); return SEGMENT; YY_BREAK case 23: YY_RULE_SETUP -#line 34 "minccalc/lex.l" -setpos(); return IF; +#line 34 "lex.l" +setpos(); return IN; YY_BREAK case 24: YY_RULE_SETUP -#line 35 "minccalc/lex.l" -setpos(); return ELSE; +#line 35 "lex.l" +setpos(); return TO; YY_BREAK case 25: YY_RULE_SETUP -#line 36 "minccalc/lex.l" -setpos(); return FOR; +#line 36 "lex.l" +setpos(); return IF; YY_BREAK case 26: YY_RULE_SETUP -#line 37 "minccalc/lex.l" -setpos(); return NAN; +#line 37 "lex.l" +setpos(); return ELSE; YY_BREAK case 27: YY_RULE_SETUP -#line 38 "minccalc/lex.l" -setpos(); return LT; +#line 38 "lex.l" +setpos(); return FOR; YY_BREAK case 28: YY_RULE_SETUP -#line 39 "minccalc/lex.l" -setpos(); return LE; +#line 39 "lex.l" +setpos(); return NAN; YY_BREAK case 29: YY_RULE_SETUP -#line 40 "minccalc/lex.l" -setpos(); return GT; +#line 40 "lex.l" +setpos(); return LT; YY_BREAK case 30: YY_RULE_SETUP -#line 41 "minccalc/lex.l" -setpos(); return GE; +#line 41 "lex.l" +setpos(); return LE; YY_BREAK case 31: YY_RULE_SETUP -#line 42 "minccalc/lex.l" -setpos(); return EQ; +#line 42 "lex.l" +setpos(); return GT; YY_BREAK case 32: YY_RULE_SETUP -#line 43 "minccalc/lex.l" -setpos(); return NE; +#line 43 "lex.l" +setpos(); return GE; YY_BREAK case 33: YY_RULE_SETUP -#line 44 "minccalc/lex.l" -setpos(); return NOT; +#line 44 "lex.l" +setpos(); return EQ; YY_BREAK case 34: YY_RULE_SETUP -#line 45 "minccalc/lex.l" -setpos(); return AND; +#line 45 "lex.l" +setpos(); return NE; YY_BREAK case 35: YY_RULE_SETUP -#line 46 "minccalc/lex.l" -setpos(); return OR; +#line 46 "lex.l" +setpos(); return NOT; YY_BREAK case 36: YY_RULE_SETUP -#line 47 "minccalc/lex.l" +#line 47 "lex.l" +setpos(); return AND; + YY_BREAK +case 37: +YY_RULE_SETUP +#line 48 "lex.l" +setpos(); return OR; + YY_BREAK +case 38: +YY_RULE_SETUP +#line 49 "lex.l" { setpos(); yylval.ident = new_ident(yytext); return IDENT; } YY_BREAK -case 37: +case 39: YY_RULE_SETUP -#line 52 "minccalc/lex.l" +#line 54 "lex.l" { setpos(); yylval.real = atof(yytext);; return REAL; } YY_BREAK -case 38: -/* rule 38 can match eol */ +case 40: +/* rule 40 can match eol */ YY_RULE_SETUP -#line 57 "minccalc/lex.l" +#line 59 "lex.l" setpos(); YY_BREAK -case 39: +case 41: YY_RULE_SETUP -#line 58 "minccalc/lex.l" +#line 60 "lex.l" setpos(); return yytext[0]; YY_BREAK -case 40: +case 42: YY_RULE_SETUP -#line 61 "minccalc/lex.l" +#line 63 "lex.l" ECHO; YY_BREAK -#line 979 "minccalc/lex.c" +#line 1029 "progs/minccalc/lex.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1230,6 +1280,14 @@ else ret_val = EOB_ACT_CONTINUE_SCAN; + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; @@ -1259,7 +1317,7 @@ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 103 ) + if ( yy_current_state >= 108 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1287,11 +1345,11 @@ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 103 ) + if ( yy_current_state >= 108 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 102); + yy_is_jam = (yy_current_state == 107); return yy_is_jam ? 0 : yy_current_state; } @@ -1645,7 +1703,9 @@ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); - + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; @@ -1663,6 +1723,8 @@ ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); @@ -1721,8 +1783,8 @@ /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ @@ -1961,7 +2023,7 @@ #define YYTABLES_NAME "yytables" -#line 61 "minccalc/lex.l" +#line 63 "lex.l"
--- a/progs/minccalc/lex.l +++ b/progs/minccalc/lex.l @@ -1,7 +1,7 @@ %{ #include <string.h> #include "node.h" -#include "y.tab.h" +#include "gram.h" int lexpos = 0; #define setpos() yylval.pos = lexpos; lexpos += yyleng @@ -19,6 +19,8 @@ abs setpos(); return ABS; max setpos(); return MAX; min setpos(); return MIN; +imax setpos(); return IMAX; +imin setpos(); return IMIN; exp setpos(); return EXP; log setpos(); return LOG; sin setpos(); return SIN;
--- a/progs/minccalc/minccalc.man1 +++ b/progs/minccalc/minccalc.man1 @@ -228,6 +228,8 @@ prod - the product of the elements of max - the maximum value of min - the minimum value of + imax - the index of the maximum value of + imin - the index of the minimum value of V[s] - the s'th element of vector V with origin 0. Symbol names are introduced into a global symbol table by assignment
--- a/progs/minccalc/node.c +++ b/progs/minccalc/node.c @@ -17,6 +17,8 @@ { NODETYPE_LEN, "len" }, { NODETYPE_MAX, "max" }, { NODETYPE_MIN, "min" }, + { NODETYPE_IMAX, "imax" }, + { NODETYPE_IMIN, "imin" }, { NODETYPE_IDENT, "ident" }, { NODETYPE_REAL, "real" }, { NODETYPE_LET, "let" },
--- a/progs/minccalc/node.h +++ b/progs/minccalc/node.h @@ -39,6 +39,8 @@ NODETYPE_LEN, NODETYPE_MAX, NODETYPE_MIN, + NODETYPE_IMAX, + NODETYPE_IMIN, NODETYPE_IDENT, NODETYPE_REAL, NODETYPE_LET,
deleted file mode 100644 --- a/progs/minccalc/y.tab.h +++ /dev/null @@ -1,134 +0,0 @@ -/* A Bison parser, made from gram.y, by GNU bison 1.75. */ - -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -#ifndef BISON_Y_TAB_H -# define BISON_Y_TAB_H - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - NAN = 258, - IN = 259, - TO = 260, - IDENT = 261, - REAL = 262, - AVG = 263, - PROD = 264, - SUM = 265, - LET = 266, - NEG = 267, - LEN = 268, - MAX = 269, - MIN = 270, - ISNAN = 271, - SQRT = 272, - ABS = 273, - EXP = 274, - LOG = 275, - SIN = 276, - COS = 277, - TAN = 278, - ASIN = 279, - ACOS = 280, - ATAN = 281, - CLAMP = 282, - SEGMENT = 283, - LT = 284, - LE = 285, - GT = 286, - GE = 287, - EQ = 288, - NE = 289, - NOT = 290, - AND = 291, - OR = 292, - IF = 293, - ELSE = 294, - FOR = 295 - }; -#endif -#define NAN 258 -#define IN 259 -#define TO 260 -#define IDENT 261 -#define REAL 262 -#define AVG 263 -#define PROD 264 -#define SUM 265 -#define LET 266 -#define NEG 267 -#define LEN 268 -#define MAX 269 -#define MIN 270 -#define ISNAN 271 -#define SQRT 272 -#define ABS 273 -#define EXP 274 -#define LOG 275 -#define SIN 276 -#define COS 277 -#define TAN 278 -#define ASIN 279 -#define ACOS 280 -#define ATAN 281 -#define CLAMP 282 -#define SEGMENT 283 -#define LT 284 -#define LE 285 -#define GT 286 -#define GE 287 -#define EQ 288 -#define NE 289 -#define NOT 290 -#define AND 291 -#define OR 292 -#define IF 293 -#define ELSE 294 -#define FOR 295 - - - - -#ifndef YYSTYPE -#line 15 "gram.y" -typedef union { -int pos; -node_t node; -double real; -ident_t ident; -} yystype; -/* Line 1281 of /usr/share/bison/yacc.c. */ -#line 127 "y.tab.h" -# define YYSTYPE yystype -#endif - -extern YYSTYPE yylval; - - -#endif /* not BISON_Y_TAB_H */ -
--- a/progs/mincpik/mincpik +++ b/progs/mincpik/mincpik @@ -432,7 +432,7 @@ $bw = int($bh/10); # get range if not defined - if(!defined(@{$opt{'image_range'}[0]})){ + if(!defined($opt{'image_range'}[0])){ print STDERR "Getting image range\n" if $opt{'verbose'}; @buf = split(/\n/, `mincstats -min -max -quiet $infile`);
--- a/progs/mincstats/mincstats.c +++ b/progs/mincstats/mincstats.c @@ -521,7 +521,7 @@ double sigma_T; double mu_T; double mu_k; - int sum; + double sum; int k_low, k_high; double mu_0, mu_1, mu; @@ -530,12 +530,12 @@ return (0.0); } - sum = 0; + sum = 0.0; for (i = 0; i < hist_bins; i++) - sum += histo[i]; + sum += (double)histo[i]; for (i = 0; i < hist_bins; i++) - p[i] = histo[i] * 1.0 / sum; + p[i] = (double)histo[i] / sum; mu_T = 0.0; for (i = 0; i < hist_bins; i++)